Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Форматы представления десятичных чисел



Упакованные BCD-числа хранятся по две цифры в байте в виде четырехбитовых групп, называемых тетрадами, причем каждая тетрада представляет собой двоичную комбинацию, соответствую­щую одной десятичной цифре, т.е. двоичное число в диапазоне 0000b – 1001b.

Неупакованное BCD-число содержит одну десятичную цифру в младшей тетраде байта, старшая тетрада должна быть нулевой, однако для команд сложения и вычитания содержимое старшей тетрады несущественно.

Команды десятичной коррекции упакованных чисел

Для упакованных десятичных чисел допустимы только опера­ции сложения и вычитания. Каждая операция выполняется в два этапа.

На первом выполняется операция – сложение или вычитание (add, adc, sub, sbb) двух упакованных десятичных чисел, первое из которых должно находиться в регистре AL, на втором – деся­тичная коррекция результата в регистре AL (daa, das).

Рассмотрим подробнее одну из команд коррекции – daa, кор­рекция после сложения BCD-чисел.

После первого этапа – двоичного сложения правильных BCD-чисел возможно появление неправильного BCD-результата в двух ситуациях:

· получена недопустимая тетрада, т.е. тетрада, двоичный экви­валент которой больше 9;

· получена допустимая тетрада, но при сложении из нее возник двоичный перенос с весом 16, в то время как правильный вес единицы переноса должен быть равен 10.

Отметим, что перенос из младшей тетрады фиксируется флагом AF, а из старшей – CF.

Алгоритм выполнения команды daa состоит из двух шагов:

· если AF=1 или младшая тетрада регистра AL содержит запре­щенную комбинацию, к содержимому AL прибавляется 06 и флаг AF устанавливается в 1;

· если CF=1 или старшая тетрада регистра AL содержит запре­щенную комбинацию, к содержимому AL прибавляется 60h и флаг CF устанавливается в 1.

Например. Содержимое регистров AL=65h и BL=28h, что соответ­ствует десятичным числам 65 и 28. Выполним их сложение


add AL, BL; AL=8Dh, AF=0, CF=0, ZF=0
daa; AL=93h, AF=0, CF=0, ZF=0

и вычитание


sub AL, BL; AL=3Dh, AF=1, CF=0, ZF=0

das; AL=37h, AF=1, CF=0, ZF=0

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

Команды десятичной коррекции неупакованных чисел

Для неупакованных чисел или, как их еще называют ASCII-чисел, существуют аналогичные команды коррекции после сложения – aaa и вычитания – aas. Сложение и вычитание ASCII-чисел также выполняется в два этапа.

Кроме того, над ASCII-числами допустимо выполнение опера­ций умножения и деления.

Умножение ASCII-чисел выполняется в два этапа:

· умножение одноразрядных сомножителей, представленных байтами, в которых младшие тетрады содержат десятичные цифры, а старшие тетрады – нулевые. Умножение выполняется командой mul, которая формирует в регистре AL двоичное про­изведение;

· коррекция результата с помощью команды aam, которая преоб­разует полученный результат в двухбайтовое произведение, на­ходящееся в регистрах AH (старший десятичный разряд) и AL (младший разряд).

Деление также выполняется в два этапа, но в отличие от ос­тальных команд коррекция выполняется не после, а перед вы­полнением операции:

· коррекция делимого с помощью команды aad, которая предполагает, что в регистрах AH и AL находится двухразрядное делимое, причем AH содержит цифру десятков, а AL – цифру единиц и обе старшие тетрады нулевые. Она формирует в AX соответствующее двоичное число;

· деление полученного в AX делимого на одноразрядный дели­тель, с получением частного в AL и остатка в AH.

ПРИМЕР ВЫПОЛНЕНИЯ РАБОТЫ

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

Текст программы:

 

model SMALL

stack 100h

 

dataseg

Ask1 db 0Ah, 0Dh, 'Введите первое слагаемое (не более 10 цифр): $'

Ask2 db 0Ah, 0Dh, 'Введите второе слагаемое (не более 10 цифр): $'

Buf1 db 11

Len1 db?

Opnd1 db 12 dup(? )

Buf2 db 11

Len2 db?

Opnd2 db 12 dup(? )

ResT db 0Ah, 0Dh, 'Сумма '

Res db 12 dup(' '), '$'

AskCont db 0Ah, 0Dh

db 'Завершить работу - Esc, продолжить - ЛЮБАЯ Ê Ë À Â È Ø À '

db '$'

 

codeseg

startupcode

push DS

pop ES; ES < - DS

 

BEGIN:

; Ввод первого слагаемого

B1: lea DX, Ask1

mov AH, 09h

int 21h

lea DX, Buf1

mov AH, 0Ah

int 21h

cmp Len1, 0

je B1

; проверка 0-9 и очистка старш.тетрады

lea BX, Opnd1

xor CX, CX

mov CL, Len1

xor SI, SI

T1: mov AL, [BX][SI]

cmp AL, '0'

jb B1; ошибка

cmp AL, '9'

ja B1; ошибка

and AL, 0Fh

mov [BX][SI], AL

inc SI

loop T1

; прижать к правому краю

mov CL, Len1

cmp CL, 10

je E1

mov DI, 9

mov SI, CX

dec SI

P1: mov AL, [BX][SI]

mov [BX][DI], AL

dec DI

dec SI

loop P1

; обнулить лишнее

xor DI, DI

mov CL, 10

sub CL, Len1

N1: mov byte ptr [BX][DI], 0

inc DI

loop N1

E1:

; Ввод второго слагаемого

B2: lea DX, Ask2

mov AH, 09h

int 21h

lea DX, Buf2

mov AH, 0Ah

int 21h

cmp Len2, 0

je B2

; проверка 0-9 и очистка старш.тетрады

lea BX, Opnd2

xor CX, CX

mov CL, Len2

xor SI, SI

T2: mov AL, [BX][SI]

cmp AL, '0'

jb B2; ошибка

cmp AL, '9'

ja B2; ошибка

and AL, 0Fh

mov [BX][SI], AL

inc SI

loop T2

; прижать к правому краю

mov CL, Len2

cmp CL, 10

je E2

mov DI, 9

mov SI, CX

dec SI

P2: mov AL, [BX][SI]

mov [BX][DI], AL

dec DI

dec SI

loop P2

; обнулить лишнее

xor DI, DI

mov CL, 10

sub CL, Len2

N2: mov byte ptr [BX][DI], 0

inc DI

loop N2

E2:

; Сложение

mov CX, 10

clc

lea SI, Opnd1+9

lea DI, Opnd2+9

lea BX, Res+10

A1: mov AL, [SI]

adc AL, [DI]

aaa

mov [BX], AL

dec SI

dec DI

dec BX

loop A1

mov AL, 0

adc AL, 0

mov [BX], AL

; Преобразование результата в ASCII

mov CX, 11

A2: or byte ptr [BX], 30h

inc BX

loop A2

; Вывод результата

lea DX, ResT

mov AH, 09h

int 21h

; Запрос на продолжение работы

lea DX, AskCont

mov AH, 09h

int 21h

mov AH, 08h

int 21h

cmp AL, 27; ESC

je QUIT

jmp BEGIN

 

; Конец работы

QUIT: exitcode 0

end

ВАРИАНТЫ ЗАДАНИЙ

1. Имеются две группы заданий стандартной (варианты 1–5) и повышенной сложности (варианты 6–8), выберите самостоя­тельно любой вариант из какой–либо группы.

2. Введите два десятичных числа разрядностью не более 10 цифр, выполните преобразование в упакованный BCD-формат, сло­жите их и выведите результат.

3. Введите два десятичных числа разрядностью не более 10 цифр, выполните преобразование в упакованный BCD-формат, вы­чтете второе из первого и выведите результат.

4. Введите два десятичных числа, первое разрядностью не более 10 цифр, второе – из одной цифры выполните преобразование в неупакованный BCD-формат, перемножьте их и выведите ре­зультат.

5. Введите два десятичных числа разрядностью не более 10 цифр, выполните преобразование в неупакованный BCD-формат, вы­чтете второе из первого и выведите результат.

6. Введите два десятичных числа, первое разрядностью не более 10 цифр, второе – из одной цифры выполните преобразование в неупакованный BCD-формат, поделите первое на второе и выведите результат.

7. Напишите программу – калькулятор выполняющую действия + –, внутреннее представление чисел – упакованный BCD-формат.

8. Напишите программу – калькулятор выполняющую действия + – *, внутреннее представление чисел – неупакованный BCD-формат.

9. Напишите программу – калькулятор выполняющую действия + – /, внутреннее представление чисел – неупакованный BCD-формат.

КОНТРОЛЬНЫЕ ВОПРОСЫ

1. Чем отличаются упакованный и неупакованный BCD-форматы представления десятичных чисел?

2. Что такое десятичная коррекция результата арифметической операции?

3. Почему используются различные команды десятичной коррек­ции для различных арифметических операций?

4. Как организовать выполнение операций сложения и вычитания над многоразрядными операндами?

5. Зачем нужны команды десятичной арифметики?

6. Почему коррекция для деления выполняется перед операцией, а для остальных операций – после?


Лабораторная работа

 

 

Ï Î Ä Ï Ð Î Ã Ð À Ì Ì Û

ЦЕЛЬ РАБОТЫ

Цель настоящей работы – изучение приемов программирования с использованием подпрограмм.

ОСНОВНЫЕ СВЕДЕНИЯ

Описание подпрограмм

Описание подпрограммы в языке ассемблера имеет следующую структуру:


имя proc тип
...
операторы тела подпрограммы
...
ret
имя endp

Здесь «тип» - одно из слов NEAR (ближняя) или FAR (дальняя). Если тип не задан, по умолчанию принимается NEAR.

Процедура NEAR должна вызываться из того же сегмента кода, в котором она описана. Процедура FAR может вызываться из дру­гих сегментов, с другим значением регистра CS. Такие процедуры обычно используются как отдельные объектные модули или в составе библиотек.

Команда ret выполняет возврат из процедуры в вызывающую программу. Она не обязана быть последней по тексту процедуры, но является последней по порядку выполнения. Команда ret также имеет ближний и дальний варианты в зависимости от типа под­программы, внутри описания которой встретилась команда.

Допускается вложение описания подпрограммы внутрь описа­ния другой подпрограммы.

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

Вызов подпрограмм

Вызов подпрограммы выполняется командой call. Вызов также бывает ближний или дальний. При ближнем вызове в стеке запо­минается текущее значение регистра IP, используемое затем командой ret (ближней) для возврата в точку вызова. При дальнем вызове в стек заносится также значение сегментного регистра CS, что позволяет команде ret (дальней) выполнить возврат в другой сегмент.

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

Например. Пусть в сегменте данных описаны переменные:

FADDR dd?
NADDR dw?

а в сегменте кода описаны подпрограммы:

FPROC proc FAR
...
FPROC endp
NPROC proc
...
NPROC endp

Рассмотрим следующие примеры команд вызова:

call FPROC; Дальний прямой вызов п/п FPROC
call NPROC; Ближний прямой вызов п/п NPROC
call FADDR; Дальний прямой вызов п/п, чей адрес - в FADDR
call NADDR; Ближний прямой вызов п/п, чей адрес - в NADDR
call BX; Ближний косвенный вызов п/п, чей адрес - в рег.BX
call word ptr [BX]; Ближний косвенный вызов п/п, чей адрес -
; в слове, адрес которого - в BX
call dword ptr [BX]; Дальний косвенный вызов п/п, чей адрес -
; в двойном слове, адрес которого - в BX

Передача параметров

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

Чаще всего применяется передача параметров через регистры или через стек.

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

При передаче через стек программа перед вызовом заносит па­раметры в стек с помощью команды push. Обычно при этом счита­ется, что подпрограмма имеет только входные параметры (как функция в языке Си). Чтобы подпрограмма могла изменять зна­чения параметров, следует передавать ей не сами значения, а ад­реса параметров.

Для доступа к параметрам, переданным в стеке, в начале подпрограммы обычно выполняются команды:

push BP
mov BP, SP

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

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

Рассмотрим пример. Пусть подпрограмма типа near имеет два словных параметра, передаваемых через стек. В этом случае после вызова подпрограммы, сохранения и загрузки регистра BP (см. выше), стек будет выглядеть, как показано ниже:

   
BP Ü SP сохраненное значение BP
IP адрес возврата
2-й параметр параметр, занесенный в стек вторым
1-й параметр параметр, занесенный в стек первым
...  

Если описать следующую структуру:

__arg struc

__saveBP dw?

__retAddr dw?

__Param2 dw?

__Param1 dw?

__arg ends,

то доступ к параметрам можно осуществить с помощью команд:

mov AX, __Param1[BP]; загрузить в AX значение первого параметра
mov BX, __Param2[BP]; загрузить в BX значение второго параметра

Для облегчения чистки стека от переданных параметров ис­поль­зуется разновидность команды ret с операндом – числом бай­тов, которые нужно убрать из стека сразу после возврата. Это позво­ляет вызы­вающей программе не заботиться об удалении па­раметров из стека. Для нашего примера команда возврата из под­программы может выглядеть следующим образом:

ret 4

Сохранение регистров

Каждая подпрограмма должна либо сохранять значения всех регистров процессора (кроме тех, которые используются для воз­врата результатов), либо, в крайнем случае, в описании подпро­граммы должно быть четко указано, какие регистры она портит. Для сохранения регистров используется стек. Команды push слу­жат для помещения регистров в стек, а pop – для их восстановле­ния перед возвратом из подпрограммы. Сохранение регистров должно выполняться после загрузки BP (см. предыдущий параграф).

Локальные переменные

Переменные, размещенные в сегменте данных, являются ста­тическими (аналогично переменным с классом static в Си). Конечно, их можно рассматривать как локальные переменные подпрограмм, обеспечив локализацию области действия с помо­щью директивы locals (см. ниже). Однако такое статическое рас­пределение памяти под локальные переменные не соответствует понятию локальных переменных в блочных языках типа Pascal или C, поскольку время существования таких переменных – время существования программы. Для того чтобы решить данную проблему, т.е. обеспечить динамическое распределение памяти под локальные переменные, следует выделять для них память в стеке (как это делается в Pascal или C).

Предположим, что в подпрограмме должно быть две локальные переменные длиной в слово. Чтобы обеспечить выделение памяти, для них перед командами сохранения регистров следует добавить команду:

sub SP, 4

которая резервирует в стеке два слова.

После выполнения этой команды стек будет выглядеть сле­дующим образом:

   
1-я лок.пер. Ü SP
2-я лок.пер.  
BP сохраненное значение BP
IP адрес возврата
2-й параметр параметр, занесенный в стек вторым
1-й параметр параметр, занесенный в стек первым
...  

И, если определить структуру:

__locvars struc

__var1 dw?

__var2 dw?

__locvars ends,

то доступ к локальным переменным можно осуществить с помо­щью команд:

mov AX, __var1[BP-4]; загрузить в AX значение 1-й локальной переменной
mov BX, __var2[BP-4]; загрузить в BX значение 2-й локальной переменной

Чистка стека от локальных переменных должна выполняться после восстановления сохраненных регистров, это можно сделать с помощью команды:

add SP, 4

или

mov SP, BP


Поделиться:



Популярное:

  1. Античные и средневековые представления о союзных государствах
  2. Виды аудиторских заключений, структура, порядок представления
  3. Врачи не имеют представления не только о значимости питания
  4. Глава I Современные представления о ДЦП
  5. Грубое нарушение правил ведения бухгалтерского учета и представления бухгалтерской отчетности, а равно порядка и сроков хранения учетных документов,-
  6. Занятие 5. Представления о психологической помощи
  7. Изучение состава чисел из единиц.
  8. Информация. Формы представления информации
  9. Используя утверждения и визуальное воображение, вы сможете изменить свои негативные представления и приступить к созданию идеальных взаимоотношений, основанных на любви.
  10. Исторические предпосылки научного представления о педагогическом процессе как целостном явлении
  11. История становления эволюционной идеи. Сущность представления Ч. Дарвина о механизме органической эволюции. Дальнейшее развитие учения Дарвина. Современный период синтеза дарвинизма и генетики.
  12. Кодирование десятичных чисел


Последнее изменение этой страницы: 2016-03-25; Просмотров: 1358; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.074 с.)
Главная | Случайная страница | Обратная связь