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





раз. Прямое обращение к видеобуферу удобно использовать, например, в обработчиках прерываний, где запрещен вызов функций DOS и имеются ограничения на обращение к средствам BIOS.

Пусть по ходу программы необходимо вывести в нижнюю строку эк­рана предупреждающее сообщение. Для этого в программу надо включить следующие предложения:

;Пример 3-7. Вывод на экран прямой записью в видеопамять;В полях данных, адресуемых через DS. msg db 'Измерения закончены'

msg_len=S-msg ;В программном сегменте mov SI,oflset msg AX,OB800h ES,AX DI,25*80*2 CX,msg_len

;Длина строки

;О5:51->выводимая строка

mov mov mov mov eld

;Сегментный адрес видеобуфера

; Будем адресовать через ES

;Смещение к последней строке экрана

;Счетчик цикла вывода символов

;DF=0, движение по строке

;и по экрану вперед

mov AH,3 Ih

;Атрибут символов — синий по

; голубому

outscr:
lodsb

;Взятъ символ из строки в AL

stosw

;Вывод на экран символа

;из AL и его атрибута из АН

;Цикл

loop outscr

Регистры DS:SI настраиваются на адрес начала выводимой строки; ре­гистры ES:DI — на адрес требуемой позиции в видеобуфере. В регистр СХ надо поместить длину строки в байтах, а флаг DF сбросить, чтобы двигать­ся по строке вперед. На экран будет выводиться содержимое регистра АХ, в младшем байте которого должен находиться код ASCII выводимого симво­ла, а в старшем байте — атрибут символа, т.е. код цвета символа (в млад­шем полубайте) и код цвета фона (в старшем полубайте). В примере число 31h образует синие символы по бирюзовому фону. При желании можно выбрать другую комбинацию цветов, выбрав ее с помощью табл. 3.1.

Таблица 3.1. Коды цветов стандартной цветовой палитры

 

Код Цвет Код Цвет  
Oh Черный 8U Серый  
Ш Синий 9U Голубой  
2h Зеленый Ah Салатовый  
3h Бирюзовый Bh Светло-бирюзовый  
4h Красный Ch Розовый  
5h Фиолетовый Dh Светло-фиолетовый
6h Коричневый Eh Желтый  
7h Белый Fh Ярко-белый  


Глава j


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



 


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

Содержательную часть цикла вывода образуют две команды lodsb и stosw. Первая команда загружает в регистр AL код очередного символа, вторая выводит его вместе с атрибутом, хранящемся в АН, на экран. При этом после каждого выполнения команды lodsb содержимое SI увеличи­вается процессором на 1, смещая адресацию к следующему символу стро­ки; в то же время каждое выполнение команды stosw увеличивает DI на 2 (потому что команда stosw работает со словами), смещая адресацию на экране на 2 байт, т.е. как раз к позиции следующего символа.

Примеры использования команд cmps и seas можно найти в Приложении.

3.4. Использование подпрограмм

Общая идея использования подпрограмм очевидна: если в программе требуется многократно выполнять один и тот же фрагмент, его можно офор­мить в виде подпрограммы и вызвать по мере необходимости. Если под­программа не требует для своего выполнения никаких параметров и не должна возвращать в основную программу результат своей работы, то дело ограничивается оформлением текста подпрограммы в виде процедуры, за­вершающейся командой ret, и вызовом этой процедуры с помощью ко­манды call. Как уже отмечалось ранее, подпрограмма может и не образовы­вать процедуру, а быть просто частью основной программы. Важно только, чтобы у нее была входная метка, и чтобы она завершалась командой call.

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

;Примср 3-8. Вызов code segment assume delay proc push CX mov CX,2000 dell: push CX mov CX,0 de!2: loop de!2 pop CX loop dell pop CX ret delay endp main proc

подпрограммы баз параметров

cs: code, ds: data;Процсдура-подпрограмма;Сохраним СХ основной программы;Счетчик внешнего цикла;Сохраним его;Счетчик внутреннего цикла;Внутрснний цикл (64К шагов);Восстановим внешний счетчик;Внешний цикл (2000 шагов) восстановим СХ программы;Возврат в программу


 

; Настроим DS ;на сегмент данных ;Функция вывода на экран ;Адрес первой строки ;Будем выводить строки в цикле ;Вызов DOS ;Вызов подпрограммы задержки ;Прибавим к смещению длину строки ;Цикл вызовов DOS ;3авершение программы

mov AX,data

mov DS,AX

mov AH,09h

mov DX,offset nisgl

mov CX,3 cntrl: hit 2 Hi

call delay

add DX,msg_len

loop cntrl

mov AX,4COOh

hit 21h main endp code ends data segment

msgl db "Процесс стартовал ",13,10,"$' msg_len=S-msgl

msg2 db "Процесс идет ",13,10,"$' msg3 db "Процесс завершается", 13,10,'$' data nds stk segment stack

dw 128 dup О stk ends

end main

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

Подпрограмма реализует задержку с помощью вложенных циклов с командой loop, использующей в качестве счетчика шагов регистр СХ. В ос­новной программе этот регистр используется для организации цикла выво­да трех строк. Поэтому первое, что должна сделать подпрограмма — это сохранить содержимое регистра СХ, для чего естественно использовать стек. Перед завершающей командой ret регистр СХ должен быть восстановлен. Фрагмент, реализующий задержку, был описан ранее, в разделе 3.2.

Основная программа выводит на экран с помощью функции 09п три строки текста. Для упрощения программы, а также чтобы продемонстри­ровать некоторые приемы программирования, вывод строк реализован в цикле. Строки сделаны одной длины, и модификация смещения к очеред­ной строке выполняется прибаачением к содержимому регистра DX дли­ны строки. Полезно обратить внимание на организацию цикла в основной программе. В цикл, помимо команды вызова подпрограммы задержки и предложения, модифицирующего регистр DX, включена лишь команда int 2lh. Регистр АН с номером функции заново не настраивается. Это и не нужно, так как DOS, выполняя затребованную операцию, первым делом


ы^Як.



Глава 3


сохраняет все регистры программы, а перед возвратом в программу их восстанавливает. Поэтому, вызывая функции DOS (или BIOS) можно не заботиться о сохранении регистров — их содержимое система на разруша­ет. Надо только иметь в виду, что многие функции DOS и BIOS после своего завершения возвращают в программу некоторую информацию (чис­ло реально введенных символов, доступный объем памяти, номер видео­режима и т.п.). Обычно эта информация возвращается в регистре АХ, од­нако могут использоваться и другие регистры или их сочетания. Поэтому, обращаясь в программе к системным функциям, необходимо ознакомиться с их описанием и, в частности, посмотреть, какие регистры они могут использовать для возвращаемых значений.

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

В примере 3-8 подпрограмма не требовала параметров. Чаще, однако, подпрограмма должна принимать один или несколько параметров и воз­вращать результат. В этом случае необходимо организовать взаимодействие основной программы и подпрограммы. Никаких специальных средств языка для этого не существует; передачу параметров в подпрограмму и из нее программист организует по своему усмотрению. Для передачи параметров как в одну, так и в другую сторону можно использовать регистры общего назначения, ячейки памяти или стек. Например, нетрудно преобразовать подпрограмму delay из примера 3-8 так, чтобы ей можно было передавать величину требуемой задержки. Пусть эта величина (в члсле шагов внешне­го цикла) передается в регистре SI.

 

;Пример 3-8а.Подпрограмма задержки с одним параметром,
передаваемом в регистре SI
delay proc   ; Процедура - подпрограмма
  push CX ;Сохраним СХ основной программы
  mov CX,SI ;Счетчик внешнего цикла
dell: push CX ;Сохраним его
  mov cx,o ;Счетчик внутреннего цикла
de!2: loop de!2 ;Внутренний цикл (64К шагов)
  pop CX ;Восстановим внешний счетчик
  loop dell ;Внешний цикл (2000 шагов)
  pop CX восстановим СХ программы
  ret   ;Возврат в программу

 

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


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



;Пример 3-86.Подпрограмма задержки с преобразованием

;параметра, передаваемого в регистре SI

delay proc;Процедура-подпрограмма

push AX;Сохраним все

push BX;используемые

push CX;в подпрограмме

push DX; регистры

mov AX,SI;Первый сомножитель в АХ

mov BX,600;Второй экспериментально
;подобранный сомножитель

mul BX;Произведение в DX:AX

mov СХ,АХ;Нам оно нужно в СХ

dell: push CX;Сохраним его

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

de!2: loop de!2;Внутренний цикл (64К шагов)

pop CX восстановим внешний счетчик

loop dell;Внешний цикл (2000 шагов)

pop DX;Восстановим

pop CX;все сохраненные

pop BX;в начале подпрограммы

pop AX;регистры

ret;Возврат в программу

Эксперименты показали, что для получения правильной задержки значение параметра, обозначающее число секунд, следует умножать на 600. Поскольку при умножении в системе команд МП 86 первый сомно­житель должен находиться в регистре АХ, а второй не может быть непос­редственным значением и тоже, следовательно, должен быть помещен в один из регистров, и, к тому же, произведение занимает два регистра DX:AX, приходится сохранять при входе в подпрограмм)' не один регистр, как в предыдущем примере, а 4. Передаваемый в SI параметр переносится в АХ, в ВХ загружается второй сомножитель, а из полученного с помо­щью команды mul произведения используется младшая часть, находяща­яся в АХ. Таким образом, для данного варианта подпрограммы значение задержки не должно превышать 109 с (109 х 600 = 65500, что почти совпа­дает с максимально возможным значением 65535).

Следует обратить внимание на опасность, подстерегающую нас при выполнении операции умножения. Пусть значение передаваемого пара­метра состаштяет всего 5. При умножении на 600 получится число 3000, которое безусловно помещается в регистре АХ. Однако операция умноже­ния 16-разрядных операндов

mul BX

всегда, независимо от конкретной величины произведения, помещает его в пару регистров DX:AX, и, следовательно, при небольшой величине Произведения регистр DX будет обнуляться. Поэтому, хотя мы и не ис-



Глава 3


 


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

Передача параметров в подпрограмму через регистры общего назначе­ния или даже через сегментные регистры вполне возможна, однако на практике для передачи параметров чаще всего используют стек, хотя бы потому, что регистров немного, а в стек можно поместить любое число параметров. При этом применяется своеобразная методика работы со сте­ком не с помощью команд push и pop, а с помощью команд mov с кос­венной адресацией через регистр ВР, который архитектурно предназна­чен именно для адресации к стеку. Преобразуем пример 3-86 так, чтобы единственный в этом примере параметр (условная величина задержки) передавался в подпрограмму не через регистр SI, а через стек. Вызов под­программы delay в этом случае должен выполняться следующим образом:

push 2000;Проталкиваем в стек значение параметра

call delay;Вызываем подпрограмму delay

Текст подпрограммы подвергнется значительным изменениям:;Пример 3-8в. Передача параметра через стек

delay ргос  
  push CX
  push BP
  mov BP,SP
  mov CX,[BP+6]
dell: push CX
  mov cx,o
de!2: loop de!2
  pop CX
  loop dell
  pop BP
  pop CX
  ret  

;Процедура-подпрограмма

;Сохраним СХ основной программы

;Сохраним ВР

;Настроим ВР на текущую вершину стека

;Скопируем из стека параметр

;Сохраним его;,*•

;Счетчик внутреннего цикла }':';-

;Внутренний цикл (64К шагов);#

;Восстановим внешний счетчик i\-:

; Внешний цикл

восстановим ВР

;и СХ программы ||,_

;Возврат и снятие со стека \

;ненужного уже параметра gj>;

Команда call, передавая управление подпрограмме, сохраняет в стеке адрес возврата в основную программу. Подпрограмма сохраняет в стеке еще два 16-разрядных регистра. В результате стек оказывается в состоянии, изображенном на рис. 3.9.

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


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



 



ВР + 4 ВР + 6

SP


Рис. 3.9. Состояние стека в подпрограмме после сохранения регистров.

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

Параметр, полученный таким образом, используется далее в подпрог­рамме точно так же, как и в примере 3-8а.

Выполнив возложенную на нее задачу, подпрограмма восстанавлива­ет сохраненные ранее регистры и осуществляет возврат в основную про­грамму с помощью команды ret, в качестве аргумента которой указывает­ся число байтов, занимаемых в стеке отправленными туда перед вызовом подпрограммы параметрами. В нашем случае единственный параметр за­нимает 2 байт. Если здесь использовать обычную команду ret без аргумен­та, то после возврата в основную программу' параметр останется в стеке, и его надо будет оттуда извлекать (между прочим, не очень понятно, куда именно, ведь все регистры у нас могут быть заняты). Команда же с аргу­ментом, осуществив возврат в вызывающую программу, увеличивает со­держимое указателя стека на значение ее аргумента, тем самым осуществ­ляя логическое снятие параметра. Физически этот параметр, как, впро­чем, и все остальные данные, помещенные в стек, остается в стеке и будет затерт при дачьнейших обращениях к стеку.

Разумеется, в стек можно было поместить не один, а сколько угодно параметров. Тогда для их чтения надо было использовать несколько ко­манд mov со значениями смещения ВР+6, ВР+8, BP+OAh и т.д.

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

3.5. Двоично-десятичные числа

В гл. 2 уже говорилось о двоично-десятичных числах — специальном формате хранения данных, используемом в ряде технических приложе-;-ний. Часто эти числа называют BCD-числами (от binary-coded decimal, 'двоично-кодированные десятичные числа). Для обработки BCD-чисел (сло-^жения, вычитания, умножения и деления) в МП 86 предусмотрены спе­циальные команды. Рассмотрим этот вопрос на комплексном примере • обработки показаний КМОП-часов реального времени.


140_______________________________________________________________ Главаз

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

После включения компьютера вступает в работу другой таймер, кото­рый обычно называют системным. Датчиком сигналов времени для него служит кварцевый генератор, работающий на частоте 1,19318 МГц; сиг­налы от которого, после пересчета в отношении 65536:1, поступают в контроллер прерываний и инициируют прерывания через вектор 8 с час­тотой 18,2065 Гц. Эти прерывания активизируют программу BIOS, перио­дически выполняющую инкремент содержимого четырехбайтовой ячейки памяти с текущим временем, находящейся по адресу 46Ch. После включе­ния машины программы BIOS считывают из часов реального времени текущее время суток, преобразуют его в число тактов системного таймера (т.е. в число интервалов по 1/18,2065 с) и записывают в ячейку текущего времени. Далее содержимое этой ячейки наращивается уже системным таймером, работающим в режиме прерываний.

Для определения текущего времени прикладная программа может вызвать соответствующие функции прерывания 21h DOS (конкретно, с номером 2Ah для получения даты и 2Ch для получения времени суток), а может прочитать время непосредственно из часов реального времени с помощью прерывания lAli BIOS. При этом прерывание lAli позволяет, помимо чтения текущего времени (функция 02h) и текущей даты (функ­ция 04h), выполнять и целый ряд других функций, среди которых мы отметим только возможность установить «будильник», т.е. записать в мик­росхему часов значение календарного времени, когда часы должны вы­дать сигнал аппаратного прерывания. Этот сигнал через вектор 70h ини­циирует обработчик прерываний, входящий в состав BIOS, который про­веряет, возникло ли данное прерывание в результате достижения времени установки будильника (часы реального времени могут инициировать пре­рывания и по других причинам), тестирует заодно батарейное питание микросхемы, а затем посылает в оба контроллера прерываний команды конца прерываний и завершается командой iret. Однако по ходу своего выполнения обработчик прерывания 70U выполняет команду int 4Ah, которая передает управление на обработчик этого прерывания, тоже вхо­дящий в состав BIOS. Системный обработчик прерывания 4Ali ничего особенно полезного не делает, в сущности представляя собой просто про­грамму-заглушку. Однако программист имеет возможность записать в век­тор 4Ali адрес прикладного обработчика прерываний, который будет ак­тивизироваться прерыванием будильника. Функции прикладного обработ­чика определяет программист.

В примере 3-9 устанавливается прикладной обработчик прерывания 4AU, который сам по себе вызваться никогда не будет, так как по умолча­нию будильник часов реального не работает. Если, однако, прочитать си-


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

схемное время с помощью функции 02U прерывания 1АИ, прибавить к нем>' некоторую величину, например, 1 секунду, и установить будильник на это время {с помощью функции 06h прерывания lAli), то через одну секунду будет активизирован наш обработчик. В примере 3-9 этот процесс сделан бесконечным: в обработчике прерываний будильника снова вы­полняется чтение времени,'прибавление к нему 1 секунды и установка будильника на новое время. В результате наш обработчик будет вызываться каждую секунду до завершения всей программы.

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

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

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

;Пример 3-9. Чтение и обработка показаний часов

;реального времени

.586;Будут использоваться дополнительные команды

assume CS:code,DS:data

code segment use!6

main proc

mov AX.data;Настроим DS наш

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

;Сохраним исходный вектор 4Ah

mov AX,354Ah

int 2 In

mov word ptr old_4a,BX

mov word ptr old_4a+2,ES;Установим наш обработчик прерывания 4Ah

mov AX,254Ah

push DS;Сохраним DS

push CS;Настроим DS на сегмент

pop DS;команд

mov DX,offset new_4a;DS:DX->new_4a

int 21h

pop DS восстановим DS

;Установим будильник



Глава 3


mov int call mov
AH,02h lAli add_time AH,06h

;Чтение текущего времени

;Прибавим I секунду;Установим будильник на это; время int lAli;Остановим программу, чтобы наблюдать прерывания

mov AH.Olh;Функция ввода с клавиатуры

int 2Ш;3авершим программу, прибрав за собой

;Сброс будильника ;О5:ОХ=исходный вектор;Установим исходный вектор ;Завершим программу

mov AH,07h

int lAli

Ids DX,old_4a

mov AX,254Ah

int 21h

mov AX,4COOh

int 21h
main endp

;Наш обработчик прерывания от будильника

new_4a proc

;Сохраним все регистры;Сохраним еще и;сегментные регистры;Настроим DS на наш;сегмент данных;Прочитаем текущее время;из часов реального времени;Сохраним полученное;тскущее время

pusha

push DS

push ES

mov AX,seg hour

mov DS,AX

mov AH,02h

hit lAli

push CX

push DX

;Преобразуем время из двоично-десятичных упакованных

;чисел в строку символов ASCII

mov AL,CH;Перенесем часы в AL

call conv;Преобразуем старшую цифру

mov hour,AH;в ASCII и сохраним

and CH,OFh;Вьщелим младшую цифру

add CH,'0' преобразуем в ASCII

mov hour+l.CH.;и сохраним

mov AL,CL;Перенесем минуты в AL

call conv;Преобразуем старшую цифру

mov min,AH;в ASCII и сохраним

and DL,OFh;Выделим младшую цифру

add DL,'0';Преобразуем в ASCII

mov min+l,CL;и сохраним

mov AL,DH;Перенесем секунды в AL

call conv;Преобразуем старшую цифру

mov sec,AH;в ASCII и сохраним


и алгоритмы



 


and DH,OFh;Выделим младшую цифру

add DH,"0';Преобразуем в ASCII:

mov sec+l,DH;и сохраним

;Вьшедем сформированную строку на экран

mov AX,OB800h;Настроим ES на сегмент

mov ES,AX видеопамяти

mov DI,160-16;Смещение к 72-му знакоместу

mov SI,offset 1юиг;О8:81->строка с временем

mov CX,8;Цикл по 8 символам

mov AH,14h;Атрибут красный по синему

eld;Движение вперед

screen: lodsb;Очередной символ в AL

stosw;Символ+атрибут на экран

loop screen;Цикл

;Сбросим будильник и установим снова на время через 1с

mov AH,07h

hit lAh

; Вернем сохраненное в стеке;текущее время;Прибавим 1 секунду;Установим будильник на;время через 1 секунду восстановим сохраненные;ранее сегментные регистры восстановим все регистры; Выход из обработчика

pop DX

pop CX

call add_time

mov AH,06h

int 1AU

pop ES

pop DS

popa

iret

new_4a endp

;Подпрограмма прибавления 1 секунды к текущему времени.;В большинстве случаев достаточно увеличить число секунд;на 1, но в конце минуты надо увеличить на 1 число минут,;а в конце часа — увеличить на 1 число часов add_time proc;Прибавим 1 к числу секунд

mov AL,DH ^Перенесем секунды в AL

call add_unit;Прибавим I

mov DH,AL;Перенесем назад в DH

jnc ok;Если CF=0, на выход

;CF=1, прибавим 1 к числу минут

mov AL,CL;Перенесем минуты в AL

call add_umt;Прибавим 1

mov CL.AL;Перенесем назад в CL

jnc ok;Если CF=0, на выход

;Перенос, прибавим 1 к числу часов

mov AL,CH;Перенесем часы в AL

call add_imit;Прибавим 1

mov CH.AL;Перенесем назад в СН



Глава 3


ok: ret ';Выход из подпрограммы

add_time endp

Подпрограмма прибавления 1 к двухразрядному BCD-числу,

Обозначающему 1 разряд времени (секунды, минуты или

;часы)

;При вызове: AL — время в BCD (секунды, минуты или часы)

;При возврате: AL — результат сложения в BCD

add_unit proc

add AL,1; Прибавим 1

daa;Коррекция после сложения

cmp AL,60h;Надо ли корректировать

;следующий разряд времени'

jb done;Нет, сумма < 60

mov AL,Oh;Да, сумма=60, должно быть О

stc;Установим CF, как признак

;переноса

jmp donel;И на выход

done: clc;Сбросим CF (переноса нет)

donel: ret;Выход из прерывания

addjanit endp

; Подпрограмма преобразования старшей половины;упакованного BCD-числа в регистре AL в код ASCII символа;в регистре АН conv ргос

mov AH,0;Обнулим АН

- shl AX,4;Сдвиг старшего полубайта AL

;в АН

add АН,'0';Преобразуем в код ASCII

ret

conv endp code ends;Сегмент данных data segment usc!6



Поделиться:




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

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


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