В графических режимах VESA, за исключением EGA graphics, доступ к видеобуферу ничем не отличается от доступа к оперативной памяти (ОЗУ, RAM). Поэтому для чтения или изменения содержимого байтов видеопамяти используются команды, выполняющие пересылку и сдвиг операндов, логические, арифметические и прочие операции.
Начиная с микропроцессора Intel 386, они могут манипулировать байтами, словами и двойными словами. Соответственно, при работе в режимах PPG одной командой можно обработать одну, две или четыре подряд расположенные на экране точки. Пересылка операндов является одним из наиболее частых действий при работе с видеопамятью. Ее выполняют команда mov и строковые команды movs, stos и lods. Напомним их основные свойства и различия.
Команда mov двухадресная, она копирует содержимое источника (source)
в приемник (destination). Приемник всегда является первым операндом, а
источник вторым. Команда допускает разные способы адресации операндов,
от этого зависит конкретный код машинной инструкции, которую Макроассемблер
формирует при компиляции. Однако оба операнда не могут одновременно находиться
в памяти. Для копирования содержимого одного байта, слова или двойного
Таблица 3.1. Пересылка из памяти в память
Пересылка байта |
Пересылка слова |
Пересылка двух слов |
mov al, fs:[di] |
mov ax, fs:[di] |
mov eax, fs:[di] |
mov gs:[si], al |
mov gs:[si], ax |
mov gs:[si], eax |
При записи операндов команды mov можно использовать имена всех сегментных регистров: cs, ds, es, fs, gs и ss. Если сегментный регистр не указан явно, то подразумевается, что это ds. В сегментном регистре должно находиться конкретное значение сегмента обычной, расширенной или видеопамяти. Смещение (относительный адрес) байта, слова или двойного слова в этом сегменте, чаще всего, указывается в индексном регистре, имя которого заключается в квадратные скобки (это признак адреса). В табл. 3.1 при чтении из памяти полный адрес операнда задается в регистрах fs:di, а при записи в память — в регистрах gs:si.
Строковые инструкции lods, movs и stos отличаются от команды пересылки (mov) следующими особенностями:
Назначение инструкций пересылки, имена которых состоят из пяти букв, показано в табл. 3.2. Местонахождение операндов у них фиксировано, и изменить его нельзя. Один из операндов может находиться в регистре-аккумуляторе, а другой или оба — в оперативной памяти. Последняя буква имени инструкции (b, w или d) указывает, какой из этих регистров является аккумулятором — al, ах или еах.
Адрес операнда, находящегося в оперативной памяти, задается в одной из двух пар регистров — ds:si или es:di. Содержимое этой пары должно быть определено в задаче до выполнения инструкций пересылки.
Таблица 3.2. Назначение строковых операций
Размер операнда в байтах |
Чтение памяти в аккумулятор accum
= ds:[si] |
Запись аккумулятора в память es:[di]
= accum |
Пересылка из памяти в память es:[di]
= ds:[si] |
1 |
lodsb |
Stosb |
movsb |
2 |
lodsw |
Stosw |
movsw |
4 |
lodsd |
Stosd |
movsd |
Очевидным недостатком строковых операций ЭДяются фиксированные сегменты
операндов источника и приемника, -егмент приемника менять нельзя, а вот
сегмент источника можно изменить. Для этого у имени операции отбрасывается
последняя буква (ь, w ли а) и явно описывается сегмент операнда источника.
Имя регистра, содержащего адрес (смещение) операнда, в этом сегменте изменить
нельзя, у
источника это регистры si или esi. Вот пример корректной записи строковых
операций:
lods byte ptr gs:[si] ; загрузка байта al = gs:[si]
movs dword ptr es: [di], fs : [si] ; копирование двойного слова
stos word ptr es:[di] ; эквивалентна stosw es:[di] = ax
Из этого примера видно, что в записи операнда источника можно указать любой сегментный ре-гистр (в данном случае gs или fs), но в записи операнда приемника может быть указан только регистр es. Если вы укажете у приемника другое имя сегментного регистра, то Макроассемблер просто использует имя es, не выдавая сообщение об ошибке.
При отсутствии пятой буквы в имени инструкции Макроассемблер не может определить размер (тип) операнда исходя из текста программы. Поэтому обязательно используется оператор ptr, перед которым указывается размер операнда — byte, word или dword. При отсутствии явного описания типа операнда Макроассемблер выдаст сообщение об ошибке.
Следует отметить, что смену сегмента операнда источника допускают все строковые операции, а не только перечисленные в табл. 3.2.
Направление пересылки. После выполнения строковой операции адрес, находящийся в индексном регистре (или в двух регистрах), увеличивается или уменьшается на размер операнда (на 1, 2 или 4). В первом случае принято говорить о пересылке в прямом направлении, а во втором — в обратном.
Перед коррекцией адреса микропроцессор проверяет состояние флага направления (direction flag), который хранится в седьмом разряде регистра флагов. Если этот разряд очищен, то содержимое индексных регистров увеличивается на размер операнда, а если он установлен, то уменьшается.
Состояние седьмого разряда регистра флагов изменяют две специальные команды eld и std. Первая (eld) очищает разряд, разрешая тем самым пересылку в прямом направлении. Вторая (std), наоборот, устанавливает разряд, разрешая пересылку в обратном направлении. Обе команды не имеют операндов. Обычное состояние флага направления — очищенное.
Таким образом, выражение "пересылка в прямом направлении" означает, что операнды записываются в память или считываются из нее в порядке увеличения их адресов. Соответственно, выражение "пересылка в обратном направлении" означает обработку операндов в порядке уменьшения их адресов.
Программные циклы. Циклом принято называть многократное возвращение на начало группы команд до тех пор, пока не будет выполнено заданное условие. Способ управления повторами цикла зависит от того, что именно является условием их прекращения. Здесь нас интересуют только циклы, управляемые по счетчику, при входе в них указывается требуемое число повторов.
Для управления циклом по счетчику предназначена специальная команда юор- Она имеет два параметра, но явно в команде указывается только один из них — метка, на которую передается управление (обычно это метка начала цикла). Неявно loop использует счетчик повторов, которым является содержимое регистра сх. При каждом выполнении команды содержимое сх уменьшается на 1, и если результат отличен от нуля, то управление передаётся на указанную в команде метку. В противном случае будет выполняться команда, расположенная после loop.
В примере 3.1 показан простой цикл очистки полного сегмента памяти, т. е. 65 536 байтов. Код очищаемого сегмента должен находиться в регистре ев. Для ускорения при каждом повторе очищаются 4 байта.
Пример 3.1 . Очистка сегмента с использованием команды mov
хог еах , еах очистка регистра еах
хог di, di di = 0, адрес начала сегмента
mov сх, 16384 сх = 16384, счетчик повторов
Ips : mov es : [di] , еах запись 4-х байтов в сегмент
add di, 04 di = di + 4 , коррекция адреса
loop Ips управление повторами цикла
В примере 3.1 цикл очистки имеет имя ips и состоит из трех команд. Первая из них очищает 4 байта памяти, вторая увеличивает хранящийся в регистре di адрес на 4, а третья повторяет цикл 16 384 раза.
Важнo
Команда loop может передать управление на метку, которая отстоит от нее
не далее чем на 128 байтов. Если это условие нарушено, то при компиляции
Макроассемблер выдаст сообщение об ошибке.
Для многократного повторения одной строковой операции предназначена команда rep, которую называют префиксом повторения. Так же, как команда loop, она использует счетчик повторов, хранящийся в регистре сх. В примере 3.2 показано применение строковой операции для очистки сегмента.
Пример 3.2. Микропрограммный цикл очистки сегмента памяти i
еах, еах ; очистка регистра еах
di, di ; di = 0, адрес начала сегмента
сх, 16384 ; сх = 16384, счетчик повторов
stosd ; очистка сегмента, указанного в ES
примере 3.2 цикл пересылки сократился до одной команды, выполнение которой микропроцессор повторяет до тех пор, пока содержимое сх не окажется равным нулю. Безусловно, микропрограммный цикл выполняется значительно быстрее, чем программный.
Инструкции rep и loop различаются способом работы со счетчиком повторов. Rep сначала проверяет содержимое регистра сх и, если оно отлично от нуля, выполняет строковую операцию и потом уменьшает содержимое сх на 1. Loop сначала уменьшает содержимое сх на 1 и в зависимости от результата повторяет или прекращает выполнение цикла. Это различие проявляется, если при входе в цикл регистр сх очищен. В таком случае указанная после rep операция не выполнится ни разу, в то время как команда loop будет повторять выполнение цикла 65 536 раз!
Таким образом, при обмене данными с видеопамятью можно использовать как обычные, так и строковые операции пересылки. В тех случаях, когда возможен выбор, предпочтение следует отдавать строковым операциям.