Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скляров И. Изучаем Assembler за 7 дней (2010).pdf
Скачиваний:
1679
Добавлен:
23.02.2015
Размер:
2 Мб
Скачать
☆

http://www.sklyaroff.ru

92

Физически команда просто вычитает операнд из нуля (операнд = 0 – операнд). При этом выполняются все правила представления чисел со знаком, о которых мы говорили выше, т. е. числа конвертируются в двоичный дополнительный код.

Команда NEG изменяет состояние следующих флагов: CF (флаг переноса), ZF (флаг нуля), SF (флаг знака), OF (флаг переполнения), AF (флаг служебного переноса), PF (флаг четности). Эти флаги можно использовать для анализа полученного результата.

Команду NEG удобно использовать для получения абсолютного значения числа следующим образом:

Mark: neg AX jl Mark

Если знак числа отрицательный будет выполнен переход на первую команду еще раз.

5.2.4. Ввод и вывод чисел

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

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

В этой программе процедура str2int преобразовывает каждое число из буфера в ASCII-формате в соответствующие бинарное число.

Другая процедура int2str преобразовывает бинарное число (результат вычисления) в число в системе счисления base в ASCII-формате.

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

К настоящему времени весь код программы вы должны в состоянии понять самостоятельно, а комментарии вам в этом помогут.

Ассемблирование и линковка выполняется обычным образом: ml numascii.asm

Листинг 5.1. Программа, демонстрирующая ввод и вывод чисел (numascii.asm)

.model small

.stack 100h

 

.data

 

mess1

db "Введите число #1: ",'$'

mess2

db "Введите число #2: ",'$'

mess3

db "Результат: ",'$'

 

mess4

db "Ошибка ввода $"

 

crlf

db 0Dh,0Ah,'$'

; перевод строки

n

db 5

; максимальный размер буфера ввода

nlength db 0

; здесь будет размер буфера после считывания

ncontents db 5 dup (?)

; содержимое буфера

buff

db 100 dup(0),'$'

; размер буфера для преобразования числа

table1

db '0123456789ABCDEF'

; таблица соответствия

base

dw 10

; указываем систему счисления в которой

 

 

; желаем выводить числа

 

 

; например: 10 - десятичная, 2 -двоичная,

http://www.sklyaroff.ru

93

.code

; 16 - шестнадцатеричная

 

 

 

; процедура вывода строки на экран

 

output PROC

 

 

mov

ah,9

 

int

21h

 

ret

 

 

output ENDP

 

 

;процедура считывания введенной строки,

;которая помещается в буфер ncontents input PROC

mov

ah,0Ah

int

21h

ret

 

input ENDP

 

;процедура преобразования числа в ASCII-формате

;из буфера ncontents в соответствующее бинарное число,

;результат преобразования помещается в AX

str2int PROC

 

 

xor

di,di

; DI указывает номер байта в буфере

xor

ax,ax

 

mov

cl,nlength

 

xor

ch,ch

 

xor

bx,bx

 

mov

si,cx

; в SI длина буфера

mov

cl,10

; множитель для MUL

next1:

 

 

mov

bl,byte ptr ncontents[di] ; взять байт из буфера

sub

bl,'0'

; вычитаем ASCII-код символа '0'

jb

error1

; если код символа меньше, чем код '0'

cmp

bl,9

; или больше, чем '9'

ja

error1

; выходим из программы с сообщением об

ошибке

 

 

mul

cx

; умножаем значение в AX на 10

add

ax,bx

; добавляем к нему новую цифру

inc

di

; увеличиваем счетчик

cmp

di,si

 

jb

next1

 

ret

 

 

error1:

 

 

mov

dx,offset mess4

mov

ah,9

 

int

21h

 

jmp

exit

 

str2int ENDP

 

 

;процедура вывода на экран числа в системе счисления base

;число передается в процедуру в регистре AX, а

;адрес результата помещается в DX

int2str PROC

http://www.sklyaroff.ru

94

; сначала очищаем буфер (заполняем нулями)

xor

di,di

mov

cx,99

zeroizing:

 

mov

byte ptr buff[di],0

inc

di

loop zeroizing

 

;заносим в di адрес последнего байта буфера,

;т. к. буфер будет заполняться от конца к началу

xor

di,di

mov

di,offset buff+99

;цикл получения цифр числа путем вычисления остатков

;от деления на основание системы

next2: xor

dx,dx

 

 

div

base

 

 

mov

si,offset table1

 

add

si,dx

 

 

mov

dl,[si]

 

 

mov

[di],dl

 

 

dec

di

 

 

cmp

ax,0

; если AX не равно 0 повторяем цикл

jnz

next2

 

 

mov

dx,di

; в DX заносим адрес результата

ret

 

 

 

int2str ENDP

 

 

 

start: mov

ax,@data

 

 

mov

ds,ax

 

 

mov

dx,offset mess1

; запрос первого числа

call

output

 

 

mov

dx,offset n

 

; принимаем ввод первого числа

call

input

 

 

mov

dx,offset crlf

 

; перевод строки

call

output

 

 

call

str2int

 

; преобразование ASCII-строки в число

 

 

 

; (результат помещается в AX)

push

ax

 

; сохраняем первое число в стек

mov

dx,offset mess2

; запрос второго числа

call

output

 

 

mov

dx,offset n

 

; принимаем ввод второго числа

call

input

 

 

http://www.sklyaroff.ru

 

 

95

call

str2int

 

; преобразование ASCII-строки в число

 

 

 

; (результат помещается в AX)

pop

bx

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

add

ax,bx

; складываем числа

push

ax

; сохраняем результат в стек

mov

dx,offset crlf

 

; перевод строки

call

output

 

 

 

mov

dx,offset mess3

; сообщение о выводе результата

call

output

 

 

 

pop

ax

 

; восстанавливаем результат из стека

call

int2str

 

; преобразовываем в ASCII-строку

call

output

 

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

exit:

 

 

; выходим из программы

mov

ax,4C00h

 

 

 

int

21h

 

 

 

end

start

 

 

 

5.2.5. Команды, работающие с целыми BCDчислами

5.2.5.1. Сложение и вычитание неупакованных BCD-чисел

Выше я уже говорил, что команды целочисленных операций, предназначенные для работы с обычными двоичными числами, будут неправильно работать с BCDчислами и наоборот. Пример сложения двух неупакованных BCD-чисел 5 и 6 с помощью команды ADD:

5 = 0000 0101

6 = 0000 0110

11 = 0000 1011

Однако в BCD-формате число 11 должно быть представлено как 0000 0001 0000 0001.

Разработчики микропроцессоров решили не вводить специальные команды для работы с BCD-числами, а ввести только несколько корректировочных команд.

Для корректировки сложения и вычитания неупакованных BCD-чисел имеются две команды:

AAA (ASCII Adjust for Addition) — коррекция результата сложения для представления в символьном виде;

AAS (ASCII Adjust for Subtraction) — коррекция результата вычитания для представления в символьном виде.

Команды AAA и AAS преобразуют содержимое регистра AL в правильную неупакованную десятичную цифру. Если результат корректировки превышает 9, то эти команды добавляют (вычитают — AAS) к содержимому регистра AH и устанавливают флаги CF и OF. Данные корректирующие команды лучше сразу использовать после команды сложения (вычитания) чисел.

Пример корректировки сложения: mov ax,5

mov bx,6