Goto... Search.. Hext Change.. Follou Previous 7 глава




Установив вектор, программа завершается с оставлением в памяти ее ^резидентной части с помощью функции 31h.

Резидентная часть программы является классическим обработчиком; программного прерывания. В первых же предложениях сохраняются регис-АХ и ВХ, используемые далее в программе, а затем содержимое сег->местного регистра CS переносится в регистр ВХ. С таким же успехом мож­но было скопировать содержимое любого из регистров DS, ES или SS, "так как в программе типа.СОМ все регистры настроены на один и тот же.сегментный адрес (см. рис. 3.2). Копирование из сегментного регистра в •'регистр общего назначения понадобился потому, что в дальнейшем нам [Придется работать с отдельными половинками сегментного адреса, а у 'сегментных регистров половинок нет.


'Команды и алгоритмы

 

 

Глава 3

Далее старшая половина сегментного адреса заносится в регистр AL, и вызовом уже.знакомой нам функции BIOS OEh этот код выводится на экран. Затем таким же образом выводится младшая половина сегментного адреса. Наконец, после восстановления регистров ВХ и АХ (в обратном порядке по отношению к их сохранению) командой iret упраштение воз­вращается в прерванную программу, которой в данном случае является COMMAND.COM.

Вывод программы (ей для наглядности было дано имя TSR.COM) для конкретного прогона показан на рис, 3.8.

FACURRENT>tsr.con

F:4CURREMT>*=


3.2. Циклы и условные переходы

Циклы, позволяющие выполнить некоторый участок программы много­кратно, в любом языке являются одной из наиболее употребительных конст­рукций. В системе команд МП 86 циклы реализуются, главным образом, с помощью команды loop (петля), хотя имеются и другие способы организа­ции циклов. Во всех случаях число шагов в цикле определяется содержимым регистра СХ, поэтому максимальное число шагов составляет 64 К.

Рассмотрим простой пример организации цикла. Пусть в программе зарезервировано место для массива размером 10000 слов, и этот массив надо заполнить натуральным рядом чисел от 0 до 9999. Эти числа, запол­няющие последовательные элементы массива, иногда называют числа­ми-заполнителями. Соответствующий фрагмент программы будет выгля­деть следующим образом:


 


Рис. 3.8. Вывод программы 3-4.

Полученный результат далек от наглядности. Действительно, разделив сегментный адрес на две половины длиной в байт каждая, мы просто записали в видеобуфер эти числа. Каждое число размером в байт можно трактовать, как код ASCII какого-то символа При выводе числа на экран эти символы и отображаются. Изображение пикового туза соответствует коду 06, а знак равенства имеет код 3Dh (см. таблицу кодов ACSII на рис. 3.1). Таким образом, сегментный адрес находящейся в памяти резидент­ной программы оказался равен 063DU, что соответствует приблизительно 25 Кбайт. Так и должно быть, так как конфигурация компьютера, исполь­зованного для подготовки примеров, предусматривала хранение большей части DOS в расширенной памяти, в области НМА. В основной памяти в этом случае располагается кусочек DOS вместе с драйверами обслужива­ния расширенной памяти и частью программы COMMAND.COM общим объемом около 25 Кбайт.

Для того, чтобы получить на экране сегментный адрес в привычной нам форме, его двоичное машинное представление необходимо преобра­зовать в коды ASCII, отображающие шестнадцатеричное (или, если угод­но, десятичное) представление этого числа. В нашем примере, чтобы по­лучить на экране изображение числа 063DU, надо было сформировать та­кую цепочку кодов ASCII (в шестнадцатеричном представлении):

30 36 33 44 68

Рассмотренный метод вывода на экран чисел в виде изображений символов, конечно, дачек от совершенства, однако подкупает свой ис­ключительной простотой и вполне может быть использован в процессе отладки резидентных программ и обработчиков прерываний, включение в которые довольно громоздких программ перекодировки может оказать­ся нежелательным или даже невозможным.

Читатель может, подготовив рассмотренный пример, загрузить несколь­ко экземпляров программы и посмотреть, как изменяются в этом случае их начальные адреса.


 

;В сегменте данных array dw 10000 dup(O);В программном сегменте mov BX,offset array mov SI,0 mov AX,0

;Адрес массива

; И ндекс

;Начальное значение

;заполнителя

mov mov inc add loop
CX, 10000 [BX][SI],AX AX SI,2 fill
fill:

; Счетчик цикла

;3аполнитель пошлем в массив

;Инкремент заполнителя

;Модификация индекса

;Команда цикла

На этапе подготовки мы заносим в регистр ВХ относительный адрес начала массива, отождествляемый с его именем array, устанавливаем на-чатьное значение индекса элемента массива в регистре SI (с таким же успехом можно было взять DI) и начальное значение числа-заполнителя. Сам цикл состоит из трех команд — единственной содержательной ко­манды засылки числа-заполнителя в очередной элемент массива (по ад­ресу, который вычисляется, как сумма содержимого регистров ВХ и SI), а также модификации числа-заполнителя и индекса очередного элемента массива. Завершающей командой loop управление передастся на метку fill, и цикл повторяется столько раз, каково содержимое СХ, в данном случае 10000 шагов.

Следует обратить внимание на команду модификации индекса — в каждом шаге к содержимому SI добавляется 2, так как массив состоит из Двухбайтовых слов. Если бы нужно было заполнить байтовый массив, то в каждом шаге содержимое регистра цикла SI следовало увеличивать на 1.

Стоит отметить некоторые детали, связанные с механизмом выпол­нения команды loop. При реачизации этой команды процессор сначата уменьшает содержимое регистра СХ на 1, а затем сравнивает полученное число с нулем. Если СХ > 0, переход на указанную метку выполняется. Если СХ = 0, цикл разрывается и процессор переходит на команду, еле-



Глава 3


Команды и алгоритмы



 


дующую за командой loop. Поэтому после нормального выхода из цикла содержимое СХ всегда равно 0.

Другое обстоятельство связано с кодированием команды loop. В ее коде под смещение к точке перехода отводится всего 1 байт. Поскольку смещение должно являться величиной со знаком, максимальное расстояние, на кото­рое можно передать управление командой loop, составляет от -128 до +127 байт (хотя довольно трудно представить себе цикл, в котором переход осу­ществляется вперед). Другими словами, тело цикла ограничивается всего 128 байтами. Если циклически повторяемый, фрагмент программы имеет боль­шую длину, цикл придется организовать другим, более сложным способом;

Организация длинного цикла

mov СХ, 10000;Счетчик цикла

fill:

; Метка начала цикла

;Тсло длинного цикла

dec cmp
СХ сх,о finish

;Дскремент счетчика цикла

;Отработано заданное число

; шагов'

;Да, на метку продолжения

; про граммы

jmp fill

;Нет, на начало цикла

;Продолжение программы

finish:

В этом, весьма типичном фрагменте мы «вручную» уменьшаем содер­жимое счетчика цикла и сравниваем полученное значение с 0. Если СХ = О, это значит, что в цикле выполнено заданное число шагов, и командой условного перехода je осущсстшмется переход на продолжение програм­мы (метка finish). Если СХ еще не равно нулю, командой безусловного перехода jmp осуществляется возврат в начало цикла. Как было показано в гл. 2, команда jmp позволяет перейти в любую точку сегмента, и огра­ничение на размер тела цикла снимается.

При необходимости организовать вложенные циклы, для сохранения счетчика внешнего цикла на время выполнения внутреннего удобно вос­пользоваться стеком. В следующем фрагменте организуется временная за­держка длительностью несколько секунд (конкретная величина задержки зависит от скорости работы процессора).

mov СХ.2000;Счетчик внешнего цикла

outer: push СХ;Сохраним его в стеке

mov CX,0;Счетчик внутреннего цикла

inner: loop inner;loop внутреннего цикла

pop СХ;Восстановим внешний счетчик

loop outer;loop внешнего цикла

Программные задержки удобно использовать при отладке программ, чтобы замедлить их работу и успеть рассмотреть их частичные результаты; иногда программные задержки позволяют синхронизовать работу аппара­туры, подключенной к компьютеру, если скорость отработки аппаратурой посыпаемых в нее из компьютера команд меньше скорости процессора. ~


В приведенном выше фрагменте внешний цикл выполняется 2000 раз; внутренний — 65536 раз. При счете числа шагов внутреннего цикла ис­пользуется явление оборачивания, которое уже упоминалось ранее. На­чальное значение в регистре СХ равно нулю; после выполнения тела цик­ла 1 раз команда loop уменьшает содержимое СХ на 1, что дает число FFFFh (которое можно рассматривать, как -1). В результате цикл повто­ряется еще 65535 раз, а в сумме — точно 64 К шагов.

Команда loop внутреннего цикла передает управление на саму себя, т.е. тело внутреннего цикла состоит из единственной команды loop. В этом нет ничего незаконного. Любая команда, в том числе и loop, требует ка­кого-то времени для своего выполнения, и повторение 64 К раз команды loop дает некоторую временную задержку (на современных процессорах порядка тысячной доли секунды).

Перейдем теперь к рассмотрению команд условных переходов.

В приведенном выше фрагменте для реализации длинного цикла ис­пользовалась команда условного перехода по равенству je. В системе ко­манд МП 86 имеется свыше трех десятков команд условных переходов, позволяющих осуществлять переходы при наличии разнообразных усло­вий: равенства, неравенства, положительности или отрицательности ре­зультата и проч. При выполнении всех этих команд процессор анализиру­ет содержимое регистра флагов и осуществляет (или не осуществляет) переход на указанную метку в зависимости от состояния отдельных фла­гов или их комбинаций. Поскольку на состояние регистра флагов влияют многие команды процессора, командами условных переходов можно пользоваться не только после команд сравнения или анализа, но и после многих других команд, если внимательно изучить влияние этих команд на флаги процессора. Приведем несколько абстрактных примеров.

cmp AX,BX
je equal
cmp SI, mem
jne notequ
hit 21h
jc syserr
or BX,BX
jz zero
in AL,DX
test AL,80h
je inpt
test AX, 7
jne found

;Сравнение двух регистров;Переход, если АХ=ВХ;Сравнение регистра и ячейки памяти;Переход, если SlOmem;Вызов DOS

;Переход, если была ошибка;и флаг CF = 1;Анализ ВХ; Переход, если ВХ=0

inpt: in AL,DX;Ввод данного из устройства

;Анализ бита 7 в данном;Ввод до тех пор, пока бит;бит 7=0(ожидание установки бита 7);Анализ битов О, I, 2 в АХ;Переход, если хотя бы 1 бит;из них установлен

test DI,OFh;Анализ битов 0...3 в DI

jz reset;Переход, если все они сброшены


 
 

Глава j

В гл. 2 отмечаюсь, что двоичные числа, записываемые в регистры про­цессора или ячейки памяти, можно рассматривать, либо как числа суще-ственно положительные, т.е. числа без знака, либо как числа со знаком. Например, адреса ячеек, разумеется, не могут быть отрицательными. По­этому число FFFFh, если по смыслу программы оно является адресом, обозначает 65535. Если, однако, то же число FFFFU получилось в ариф­метической операции вычитания 2 из 1, то его надо рассматривать, как — 1. Точно так же понятие знака бессмысленно по отношению к кодам сим­волов, которые с равным успехом могут принимать любое значение из диапазона 0...255. С другой стороны, мы можем условно считать, что коды символов первой половины таблицы ASCII положительны, а коды вто­рой половины таблицы (у них установлен старший бит) отрицательны, и использовать для обработки символов команды, чувствительные к знаку.

В составе команд условных переходов имеются две группы команд для сравнения чисел без знака (это команды ja, jae, jb, jbe, jna, jnae, jnb и jnbe) и чисел со знаком (jg> Jgc, jl, jle, jug, jiige, jnl и jnle). В аббревиатурах этих команд для сравнения чисел без знака используются слова above (выше) и below (ниже), а для чисел со знаком — слова greater (больше) и Less (меньше).

Разница между теми и другими командами условных переходов зак­лючается в том, что команды для чисел со знаком рассматривают поня­тия «больше-меньше* применительно к числовой оси -32К...О...+32К, а команды для чисел без знака — применительно к числовой оси 0...64К. Поэтому для первых команд число 7FFFh (+32767) больше числа SOOOh (-32768), а для вторых число 7FFFU (32767) меньше числа 8000U (32768). Аналогично, команды для чисел со знаком считают, что 0 больше, чем FFFFh (-1), а команды для чисел без знака — меньше.

Рассмотрим пример использования команд условных переходов для обработки символов. Пусть мы вводим с клавиатуры некоторую строку сим­волов (например, имя файла), и хотим, чтобы в программе эта строка была записана прописными буквами, независимо от того, какие буквы исполь­зовались при ее вводе. Между прочим, при вводе с клавиатуры команд DOS система всегда выполняет эту операцию, поэтом}' и команды, и ключи, и имена файлов можно вводить как прописными, так и строчными буквами — DOS во всех случаях преобразует все буквы в прописные.

Пример 3-5. Сравнение чисел без знака

code segment ;

assume cs:code,ds:data \'\

main proc i--\

mov AX,data Инициализируем:

mov DS,AX;регистр DS •)•-

;Выведем служебное сообщение |v

mov AH,09h;Функция вывода:;,

mov DX,oflset msg;Адрес сообщения, ,h

int 2 Hi \*

;Поставим запрос к DOS на ввод строки


г


Команды а алгоритмы

mov mov mov mov int mov AH,3Fh BX,0 CX,80 DX,offset buf 21h action, AX ;Функция ввода Дескриптор клавиатуры;Ввод максимум 80 байт;Адрес буфера ввода ;Фактически введено

;Превратим строчные русские буквы в прописные

mov CX,actlen
mov SI,0
filter: mov AL,buf[SI]
cmp AL,'a'
jb noletter
cmp AL/я1
ja noletter
cmp AL, 'n'
ja more
sub AL,20h
jmp store
more: cmp AL, 'p'
jb noletter
sub AL,50h
store: mov buf[SI],AL
noletter: inc SI
loop filter  

;Длина введенной строки

;Указатель в буфере

;Возьмем символ

;Меньше 'а'?

;Да, не преобразовывать

;Болыпе 'я'?

;Да, не преобразовывать

; Больше 'п1?

;Да, на дальнейшую проверку

;'а'...'п'. Преобразуем в прописную

;На сохранение в буфере

;Меньше 'р1 (псевдографика)?

;>'п', <'р'. Не изменять

;'р'...'я'. Преобразуем в прописную

;Отправим назад в buf

;Сместим указатель

;Цикл по всем символам

;Функция вывода;Дескриптор экрана;Длина сообщения;Адрес сообщения ;Остановим программу ;в ожидании нажатия клавиши
AH,40h BX,1 CX,actlen DX,oflset buf 21h AH,01 2 111

;Выведем результат преобразования на экран для контроля

mov

mov

mov

mov

int

mov

int;3авершим программу

mov AX,4COOh

; Буфер ввода

int 2 In main endp code ends data segment msg db 'Вводите! S' buf db 80 dup (' ') actlendw 0 data ends stk segment stack dw 128 dup (') stk ends end main



Глава j


Цдчанды и алгоритмы



 


 


В начале программы на экран выводится служебное сообщение «Вво­дите! «, которое служит запросом программы, адресованным пользовате­лю. Далее с помощью функции DOS 3Fh выполняется ввод строки текста с клавиатуры. Функция 3Fh может вводить данные из разных устройств — файлов, последовательного порта, клавиатуры. Различные устройства иден­тифицируются их дескрипторами. При работе с файлами дескриптор каж­дого файла создается системой в процессе операции открытия или созда­ния этого файла, а для стандартных устройств — клавиатуры, экрана, принтера и последовательного порта действуют дескрипторы, закрепляе­мые за этими устройствами при загрузке системы. Для ввода с клавиатуры используется дескриптор 0, для вывода на экран дескриптор 1.

При вызове функции 3Fh в регистр ВХ следует занести требуемый дескриптор, в регистр DX — адрес области в программе, выделенной для приема вводимых с клавиатуры символов, а в регистр СХ — максималь­ное число вводимых символов. Мы считаем, что пользователь не будет вводить более 80 символов. Можно ввести и меньше; в любом случае ввод строки следует завершить нажатием клавиши <Enter>. Функция 3Fh, от­работав, вернет в регистре АХ решхьное число введенных символов (вклю­чая коды 13 и 10, образуемые при нажатии клавиши <Enter>). В примере 3.5 число введенных символов сохраняется в ячейке actlen с целью ис­пользования далее по ходу программы.

Далее в цикле из actlen шагов выполняется анализ каждого введенно­го символа путем сравнения с границами диапазонов строчных русских букв. Русские строчные буквы размещаются в двух диапазонах кодов ASCII (а...п и р...с), причем для преобразования в прописные букв первого диа­пазона их код следует уменьшать на 20h, а для преобразования букв вто­рого диапазона — на 50h. Поэтому анализ проводится с помощью четырех команд сравнения стр и соответствующих команд условных переходов. Модифицированный символ записывается на то же место в буфере buf.

После завершения анализа и преобразования введенных символов, выполняется контрольный вывод содержимого buf на экран. Поскольку мы заранее не знаем, сколько символов будет введено, вывод на экран осуществляется функцией 40h, среди параметров которой указывается число выводимых символов. Так же, как и в случае функции ввода 3Fh, для функции вывода 40h в регистре ВХ необходимо указать дескриптор устройства ввода, в данном случае экрана, а в регистре DX — адрес выво­димой строки.

Коды символов являются числами без знака, и использование в дан­ном случае команд условных переходов для чисел без знака представляет­ся логичным и даже единственно возможным. Если, однако, внимательно рассмотреть понятия больше-меньше для чисел со знаком и без знака, то легко увидеть, что пока мы сравниваем друг с другом только «положи­тельные» или только «отрицательные» числа, команда ja эквивалентна команде jg, а команда jb эквивалентна команде J1. Однако при сравнении, например, кодов цифр с кодами русских букв, правильный результат можно получить лишь при использовании команд переходов для чисел


без знака. Впрочем, всегда нагляднее и надежнее использовать те коман­ды, которые соответствуют существу рассматриваемых данных, даже если такой же правильный результат получится и при использовании «непра­вильных» команд.

Более отчетливо разница между числами со знаком и без знака прояв­ляется при использовании арифметических операций, например, опера­ций умножения или деления. Здесь для чисел со знаком и чисел без знака предусмотрены отдельные команды:

inul — команда умножения чисел без знака; imul — команда умножения чисел со знаком; div — команда деления чисел без знака; idiv — команда деления чисел со знаком.

Поясним различия этих команд на формальных примерах.

;Умножение положительных чисел со знаком

mov AL,5;Первый сомножитель=5

mov BL.7;Второй сомножитель=7

mul BL;AX=0023h=35

mov AL,5;Первый сомножитель=5

mov BL,7;Второй сомножитель=7

imul BL;AX=0023h=35

Обе команды, mul и imul, дают в данном случае одинаковый резуль­тат, так как положительные числа со знаком совпадают с числами без знака. Не так обстоит дело при умножении отрицательных чисел.

;Умножение отрицательных чисел со знаком

mov AL,OFCh;Первый сомножитель=252

mov BL,4;Второй сомножитель=4

mul BL;AX=03FOh= 1008

mov AL,OFCh;Первый сомножитель=-4

mov BL,4;Второй сомножитель=4

imul BL;AX=FFFO=-16

Здесь действие команд mul и imul над одними и теми же операндами дает разные результаты. В первом примере число без знака FCh, которое интерпретируется, как 252, умножается на 4, давая в результате число без знака 3FO, т.е. 1008. Во втором примере то же число FCh рассматривается, как число со знаком. В этом случае оно составляет -4. Умножение на 4 дает FFFOh.T.e.-16.



Глава 3


г


алгоритмы



 


3.3. Обработка строк

Для работы со строками, или цепочками символов или чисел (т.е. попросту говоря, с массивами произвольных данных) в МП предусмот­рен ряд специальных команд:

movs — пересылка строки;

cmps — сравнение двух строк;

seas — поиск в строке заданного элемента;

lods — загрузка аккумулятора (регистров AL или АХ) из строки;

stos — запись элемента строки из аккумулятора (регистров АХ или AL).

Эти команды очень удобны, однако их использование сопряжено с некоторыми трудностями, так как процессор, выполняя эти команды, неявным образом использует ряд своих регистров. Только если все эти регистры настроены должным образом, команды будут выполняться пра­вильно. В результате включение в программу предложения с командой, например, movs, требует иной раз 6—7 дополнительных предложений, в которых осуществляется подготовка условий для правильного выполне­ния этой команды.

Хотя команды обработки строк, как правило, включаются в програм­му без явного указания операндов, однако каждая команда, в действи­тельности, использует два операнда. Для команд seas и stos операндом-источником служит аккумулятор, а операнд-приемник находится в памя­ти. Для команды lods, наоборот, операнд-источник находится в памяти, а приемником служит аккумулятор. Наконец, для команд movs и cmps оба операнда, и источник, и приемник, находятся в памяти.

Вес рассматриваемые команды, выполняя различные действия, под­чиняются одинаковым правилам, перечисленным ниже. Операнды, нахо­дящиеся в памяти, всегда адресуются единообразно: one ранд-источник через регистры 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,OFOOOh;3анесем в DS/

mov DS,AX;сегментный адрес ПЗУ BIOS

mov SI,OFFF5h;Смещение к интересующему нас полю

mov AX,data;Настроим ES

mov ES,AX;на сегмент данных программы

mov DI,ofTset Ью8;Смещение к полю для хранения даты

mov СХ,8;Перенести 8 байт

eld Движение по строке вперед

rep movsb;Перенос байтов

;Выведем полученную информацию на экран

mov AX,data;Теперь настроим DS

mov DS,AX;на сегмент данных программы

mov AH,40h;Функция вывода

mov BX,1;Дескриптор экрана

mov CX,8;Вывести 8 байт

mov DX,offset bios;Смещение к строке

int 21h;Вызов DOS

;В сегменте данных

bios db 8 dup(');Поле для хранения даты

Известно, что в ПЗУ BIOS, сегментный адрес которого составляет FOOOh (см. рис. 1.5), наряду с программами управления аппаратурой ком­пьютера, хранятся еще и некоторые идентификаторы. Так, в восьми бай­тах ПЗУ, начиная с адреса FOOOh:FFF5h, записана в кодах ASCII дата разработки ПЗУ. В примере 3.6 выполняется чтение этой даты, сохранение ее в памяти и вывод на экран для контроля. Поскольку интересующая нас дата хранится в ПЗУ BIOS в кодах ASCII, никаких преобразований содер­жимого этого участка ПЗУ перед выводом на экран не требуется.

В программе осуществляется настройка всех необходимых для выпол­нения команды movs регистров (DS:SI, ES:DI, СХ и флага DF) и одной командой movsb с префиксом гср содержимое требуемого участка ПЗУ переносится в поле bios. Перенос строки байтами подчеркивает се формат (в строке записаны байтовые коды ASCII), однако в нашем примере, при четном числе переносимых байтов, более эффективно осуществить пере­нос по словам. В этом варианте команда movs будет фактически повто­ряться не 8 раз, а только 4. Для этого достаточно занести в СХ число 4 (вместо 8) и использовать вариант команды movsw.



Глава 3


Команды и алгоритмы



 


Для выполнения команды niovs нам пришлось настроить сегментный регистр DS на сегмент BIOS. Если в дальнейшем предполагается обраще­ние к полям данных программы, как это имеет место в примере 3-6, в регистр DS следует занести сегментный адрес сегмента данных. После этого, настроив остальные регистры для вызова функции 40h, прочитанную из BIOS строку можно вывести на экран.

В рассмотренном примере неявно предполагалось, что программа бу­дет в дальнейшем как-то использовать полученную из BIOS информацию, Если задача программы заключается просто в выводе на экран даты вы­пуска BIOS, то нет необходимости сначала копировать эту дату из BIOS в поля данных программы, а потом выводить ее на экран. Можно было по­ступить гораздо проще: настроив регистр DS на сегмент BIOS, а регистр DX на адрес строки с датой, вызвать функцию 40h и вывести на экран текст непосредственно из сегмента BIOS. Тогда содержательная часть про­граммы сократится в два раза и примет такой вид:

mov mov mov mov mov mov hit
AX.OFOOOh DS,AX AH,40h BX,1 CX,8 DX,OFFF5h 21h

;Настроим DS;на сегмент BIOS;Функция вывода;Дескриптор экрана;Вывести 8 байт;Смещение к дате;Вызов DOS

Приведенный фрагмент не имеет отношения к данному разделу, так как в нем уже нет команд обработки строк. В то же время он подчеркивает важность сегментных регистров и гибкость сегментной адресации. Функ­ция 40h ожидает найти адрес выводимой на экран строки в регистрах DS:DX, и никакие другие регистры в этом случае использовать нельзя. С другой стороны, эти регистры можно настроить на любой участок памяти и вывести на экран (а также и на принтер, в файл или в последователь­ный порт) данные откуда угодно.

Рассмотрим теперь пример работы с командами lods и stos, которые можно использовать как по отдельности, так и в паре друг с другом. Эти команды очень удобны, в частности, для прямого обращения к видеопамяти.

К экрану, как и к любому другому устройству, входящему в состав компьютера, можно обращаться тремя способами: с помощью функций DOS (прерывание 21h), с использованием прерывания BIOS (для управ­ления экраном используется прерывание 10h) и, наконец, путем прямо­го программирования аппаратуры, в данном случае видеобуфера (видео­памяти). Функции DOS позволяют выводить только черно-белый текст и имеют ряд других ограничений (нельзя очистить экран, нет средств пози­ционирования курсора); при использовании прерывания BIOS все эти ограничения снимаются, однако программирование с помощью средств BIOS весьма трудоемко; наконец, прямая запись в видеопамять, предос­тавляя возможность вывода цветного текста в любую точку экрана, явля­ется процедурой очень простой и, к тому же, повышает скорость вывода (по сравнением с использованием системных средств) в десятки и сотни



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: