Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЦМПУ / Новая папка (1) / ЦИМПУ(atmega 128).doc
Скачиваний:
102
Добавлен:
16.04.2015
Размер:
4.2 Mб
Скачать

3.5 Контрольные вопросы

  1. На какие группы можно разделить команды? Приведите к каждой группе по несколько команд.

  2. Перечислите способы адресации к областям памяти микроконтроллера.

  3. За сколько тактов осуществляется выполнение команды RCALL?

  4. Укажите порядок выполнения команды RET.

  5. Сравните процесс выполнения команд RCALL и RET.

  6. В какой последовательности сохраняется и извлекается содержимое регистров микроконтроллера в подпрограммах?

  7. Укажите разряды регистра состояния SREG.

  8. Как осуществляется загрузка данных в регистры микроконтроллера?

  9. Опишите работу команд обмена между РОН и памятью данных.

  10. Для чего предназначены команды LDI, MOV, SBRC, CPI, BRBC?

  11. Перечислите флаги и охарактеризуйте их. 12. Расскажите про прямую адресацию 13. Расскажите про косвенную адресацию 14. Расскажите про относительную косвенную адресацию 15. Расскажите про косвенную адресацию с постинкрементом и с преддекрементом

3.6 Содержание отчета по лабораторной работе

  1. Краткое теоретическое введение.

  2. Алгоритм программы самостоятельного задания.

  3. Листинг программы и проектного файла с комментариями.

  4. Выводы по лабораторной работе.

Примечание: После выполнения данной лабораторной работы, необходимо ознакомится с материалами лабораторной работы №11 «Система команд микроконтроллера на примере микроконтроллеров AVR фирмы ATMEL». Данная работа находится на сервере кафедры АИСУ

Лабораторная работа №4 «Выполнение арифметических операций»

4.1 Цель работы: Исследовать особенности выполнения арифметических команд в микроконтроллере ATmega128 и пути использования МК для программной реализации обработки информации.

4.2 Теоретическое введение

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

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

Основные арифметические функции соответствующих команд МК – это сложение и вычитание двух чисел. Команда ADD складывает, а команда SUB вычитает данные регистра Rr из регистра Rd и запоминает результат в регистре Rd. Для учета возможного переполнения МК содержит флаг переноса, который работает как девятый бит регистра. Команда вычитания использует флаг переноса как флаг заема. Если он устанавливается после команды вычитания в "1", то это значит, что число в регистре Rr больше, чем в Rd.

Кроме названных арифметических операций в системе команд МК имеются команды сложения и вычитания с учетом переноса и с непосредственным операндом, расположенным во втором байте команды и т д. Примеры выполнения арифметических команд приведены в задании 1.

В задании 4 исследуется вариант алгоритма подпрограммы целочисленного умножения и деления для 8-ми 16-ти разрядных чисел. В задании приводятся тексты программ для 8-разрядных чисел. Программы для 16-разрядных чисел строятся аналогично. Большинство предлагаемых программ выполнено в двух вариантах. Первый оптимизирован с точки зрения длины результирующего программного кода, а второй – с точки зрения времени исполнения.

Представления целых чисел:

В двоичной системе счисления числа представляются с помощью комбинации единиц и нулей, знака “минус” и знака разделяющей точки между целой и дробной частью числа. Например, десятичное число – 1.312510 в двоичном виде будет выглядеть как – 1001.01012. Но в компьютере мы не можем хранить и обрабатывать символы знака и разделяющей точки – для “машинного” представления чисел могут использоваться только двоичные цифры (0 и 1). Если операция выполняется только с неотрицательными числами, то формат представления очевиден. В машинном слове из 8 бит можно представить числа в интервале от 0 до 255. Например:

00000000 = 0

00000001 = 1

00101001 = 41

10000000 = 128

11111111 = 255

В общем случае n-битовая последовательность двоичных цифр an-1 an-2a1 a0 может быть интерпретирована как целое число А, значение которого равно

Прямой код

Существует несколько представлений о едином формате представления как положительных, так и отрицательных чисел. Все их объединяет то, что старший бит слова (с точки зрения европейца – самый левый, или бит, которому при представлении числа без знака должен быть приписан самый большой вес) является битом хранения знака или знаковым разрядом. Все последующие биты слова представляют значащие разряды числа, которые в каждом формате интерпретируются по-своему. Значение 1 в знаковом разряде интерпретируется как представление всем словом отрицательного числа.

Простейшим форматом, который использует знаковый разряд, является прямой код. В n-разрядном двоичном слове n-1 значащих разрядов представляют величину числа. Например:

00010010 = +18

10010010 = -18

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

Формат представления чисел в прямом коде неудобен для использования в вычислениях. Поэтому при реализации арифметических операций в АЛУ над целыми числами наиболее широкое применение находит другой формат, получивший наименование дополнительного кода.

Дополнительный код

Как и в прямом, в дополнительном коде старший разряд в разрядной сетке отводится для представления знака числа. Остальные разряды интерпретируются не так, как в прямом коде. В таблице 4.1. перечислены основные свойства дополнительного кода и правила выполнения арифметических операций в дополнительном коде.

Таблица 4.1 Основные свойства дополнительного кода и правила выполнения операций

Диапазон представления

на n-разрядной сетке

от -2n-1 до 2n-1 - 1

Количество кодовых комбинаций, соответствующих числу 0

Одна (00000000)

Переход в дополнительный код

Инвертировать значение в каждом разряде представления исходного числа (положительного или отрицательного), а затем сложить образовавшееся число с числом 00000001 по правилам сложения чисел без знака

Расширение разрядности представления

Добавить дополнительные разряды слева и заполнить их значениями, равными значению в знаковом разряде исходного представления

Определение переполнения при сложении

Если оба слагаемых имеют одинаковые знаки (оба положительны или отрицательны), то переполнение возникает в том и только в том случае, когда знак суммы оказывается отличным от знаков слагаемых

Правило вычитания

Для вычитания числа В из числа А инвертировать знак числа В, как описано выше, и сложить преобразованное число с А по правилам сложения в дополнительном коде

Рассмотрим n-разрядное двоичное целое число А в дополнительном коде. Если А положительно, то значение его знакового разряда an-1 равно 0. В значащих разрядах будет представлена абсолютная величина числа точно так же, как и в прямом коде:

Очевидно, что диапазон представления положительных чисел n-разрядным дополнительным кодом простирается от числа 0 до числа 2n-1 – 1 (для этого числа значения во всех значащих разрядах равны 1). Для представления большего числа потребуется расширение разрядной сетки.

Теперь перейдем к отрицательным числам. Знаковый разряд an-1 дополнительного кода отрицательного числа А (А<0) равен 1. В n-1 значащих разрядах может содержаться произвольная комбинация нулей и единиц, а также комбинаций может быть 2n-1. Следовательно, имеется потенциальная возможность представить отрицательные числа от -1 до -2n-1. Желательно таким образом установить соответствие между двоичными комбинациями и целыми отрицательными числами, чтобы арифметические операции над ними выполнялись по тем же правилам, что и над числами без знака. В формате целых чисел без знака для вычисления числа по его двоичному представлению следует присвоить старшему разряду в разрядной сетке вес +2n-1. При представлении, включающим и знаковый разряд, это приводит к тому, что желаемые арифметические свойства сохраняются, если вес этого разряда (старшего в разрядной сетке представления) будет равен -2n-1. Это соглашение и используется при представлении чисел в дополнительном коде. Формально для отрицательного числа в дополнительном коде соблюдается соотношение:

Примеры представления чисел в дополнительном коде:

00010010 = +18

11101110 = -18

00000111 = 7

11111001=-7

10001000 = -120

01111000 = 120

01001011 = 75

11001000 = -56

Обратный код получается путём инверсии заданного числа, например:

дано число 10101101, делаем инверсию числа получаем 11010010, причём первая единичка указывает на знак числа (1-- минус, 0 -- плюс) её инверсии не подвергаем.

Дополнительный код путем прибавления к полученному числу 11010010 числа 00000001 получаем 11010011.

Знаковые обратные двоичные коды. 

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

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

Представление дробных чисел в двоичном коде с фиксированной запятой

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

Рассмотрим, как можно записать дробное число. До сих пор мы предполагали, что двоичная запятая находится правее самого младшего разряда. Но кто сказал, что она должна всегда находиться в этом месте? Мы можем договориться, что запятая находится слева от самого старшего разряда, и тогда в такой переменной можно будет записывать только дробные числа:

Или договоримся, что она находится точно посередине переменной, и тогда мы сможем записывать смешанные числа:

Остальные случаи рассматривать не будем. Они строятся точно так же как и для целых чисел.

Представление чисел в двоичном коде с плавающей запятой

Часто приходится обрабатывать очень большие числа (например, расстояние между звёздами) или наоборот очень маленькие числа (например, размеры атомов или электронов). При таких вычислениях пришлось бы использовать числа с очень большой разрядностью. В то же время нам не нужно знать расстояние между звёздами с точностью до миллиметра. Для вычислений с такими величинами числа с фиксированной запятой неэффективны.

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

0,2*105; 0,16*10-38

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

4.2.1 Умножение беззнаковых целых восьмиразрядных чисел (8х8=16)

Две предлагаемые программы (табл. 4.2) используют один и тот же алгоритм, приведенный ниже. Программа mpy8u_c, имеющая оптимизированный код, использует циклическое повторение операций. Программа mpy8u_s, минимизирующая время исполнения, содержит последовательные повторяющиеся участки кода. Обе программы используют четыре регистра (табл. 4.3). Причем для уменьшения количества используемых регистров, длины кода и времени исполнения множитель и младший байт результата разделяют один и тот же регистр.

Таблица 4.2 Умножение беззнаковых целых восьмиразрядных чисел

Название

программы

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

Длина кода, слов

Время исполнения, такты

mpy8u_c

Беззнаковое умножение

8 х 8=16. Оптимизация кода.

9

58

mpy8u_s

Беззнаковое умножение

8 х 8=16. Оптимизация времени исполнения..

34

34

Таблица 4.3 Использование регистров программами"mpy8u_х"

Регистр

На входе программы

Внутри программы

На выходе программы

R16

“mc8u”-множимое

R17

“mp8u”-множитель

“m8uL” - младший байт результата

R18

“m8uH” - старший байт результата

R19

“mcnt8u”- счетчик цикла

Алгоритм умножения беззнаковых целых (рис. 4.1) чисел реализует следующую последовательность действий:

  1. Очистить старший байт результата.

  2. Загрузить в счетчик цикла число повторений 8.

  3. Множитель сдвинуть на один разряд вправо с использованием бита переноса С

  4. Если перенос С установлен, прибавить множимое к результату.

  5. Старший байт результата сдвинуть вправо с использованием бита переноса С.

  6. Младший байт результата/множитель сдвинуть вправо с использованием бита переноса С.

  7. Уменьшить на единицу счетчик цикла.

  8. Если счетчик цикла еще не равен нулю, перейти к шагу 4.

Рис. 4.1 Алгоритм программы “mpy8u_c” умножения 8-и разрядных целых беззнаковых чисел

Введем обозначения:

A-множимое, В-множитель, R-результат (1)

Причем пусть,

(2)

Тогда, анализируя приведенный алгоритм и имея в виду, что сдвиг двоичного числа вправо на один разряд означает деление этого числа на два, а сдвиг влево – умножение на два, нетрудно увидеть, что вычисление осуществляется по следующей формуле:

(3)

Рис. 4.2 Алгоритм программы “mpy8u_s” умножения 8-и разрядных целых беззнаковых чисел

Текст программы mpy8u_c умножения 8-и разрядных целых беззнаковых чисел, оптимизированной с точки зрения кода. (После запуска программы при помощи команды Run/Step into (F7) при очистке регистров множителя и множимого, необходимо занести значения множителя и множимого в эти регистры: в окне регистров (Alt+Shift+R) напротив значения регистров щелкнуть правой кнопкой мыши, установить десятичный формат, ввести значение).

Использование регистров (инициализация переменных)

; ******************************************************

; BASIC .ASM template file for AVR

; ******************************************************

.include "C:\VMLAB\include\m128def.inc""; определение библиотеки МК ;ATmega128, при условии расположения программы VMLAB на

;локальном диске С

.def mc8u =r16 ;множимое

.def mp8u =r17 ;множитель

.def m8uL =r17 ;младший байт результата

.def m8uH =r18 ;старший байт результата

.def mcnt8u=r19 ;счетчик цикла

reset: ; начальная метка

rjmp start

reti ; Addr $01

reti ; Addr $02

reti ; Addr $03 Вектора прерываний МК ATmega128.

reti ; Addr $04 Приведены вектора с адреса $01 по адрес $10.

reti ; Addr $05 Полностью вектора прерываний представлены

reti ; Addr $06 в приложении с назначением прерываний

reti ; Addr $07 (внешних и внутренних).

reti ; Addr $08

reti ; Addr $09

reti ; Addr $0A

reti ; Addr $0B

reti ; Addr $0C

reti ; Addr $0D

reti ; Addr $0E

reti ; Addr $0F

reti ; Addr $10

start: ldi mc8u, A ;загрузить множимое

ldi mp8u, B ;загрузить множитель

mpy8u_c: clr m8uH ;очистить старший байт результата

ldi mcnt8u,8 ;инициализировать счетчик цикла

lsr mp8u ;cдвинуть вправо множитель

m8u_1: brcc m8u_2 ;переход, если С=0

add m8uH,mc8u ;прибавить множимое к старшему

;байту результата

m8u_2: ror m8uH ;сдвинуть вправо старший байт результата

ror m8uL ; сдвинуть вправо младший

;байт результата и множитель

dec mcnt8u ;уменьшить на 1 счетчик цикла

brne m8u_1 ;переход, если счетчик цикла еще не равен 0

.exit ; конец программы

Примечание: А – числовое значение множимого, В – числовое значение множителя.

Текст программы mpy8u_s умножения 8-и разрядных целых беззнаковых чисел, оптимизированной с точки зрения времени исполнения. (После запуска программы при помощи команды Run/Step into (F7) при очистке регистров множителя и множимого, необходимо занести значения множителя и множимого в эти регистры: в окне регистров (Alt+Shift+R) напротив значения регистров щелкнуть правой кнопкой мыши, установить десятичный формат, ввести значение). Алгоритм программы представлен на рис. 4.2.

Использование регистров (инициализация переменных)

; ******************************************************

; BASIC .ASM template file for AVR

; ******************************************************

.include "C:\VMLAB\include\m128def.inc""; определение библиотеки МК ;ATmega128, при условии расположения программы VMLAB на

;локальном диске С

; Define here the variables

.def mc8u =r16 ;множимое

.def mp8u =r17 ;множитель

.def m8uL =r17 ;младший байт результата

.def m8uH =r18 ;старший байт результата

reset: ; начальная метка

rjmp start

reti ; Addr $01

reti ; Addr $02

reti ; Addr $03 Вектора прерываний МК ATmega128.

reti ; Addr $04 Приведены вектора с адреса $01 по адрес $10.

reti ; Addr $05 Полностью вектора прерываний представлены

reti ; Addr $06 в приложении с назначением прерываний

reti ; Addr $07 (внешних и внутренних).

reti ; Addr $08

reti ; Addr $09

reti ; Addr $0A

reti ; Addr $0B

reti ; Addr $0C

reti ; Addr $0D

reti ; Addr $0E

reti ; Addr $0F

reti ; Addr $10

start: ldi mc8u, A ;загрузить множимое

ldi mp8u, B ;загрузить множитель

mpy8u_s: clr m8uH ;очистить старший байт результата

lsr mp8u ; cдвинуть вправо множитель

brcc noad80 ; переход, если С=0

add m8uH,mc8u ; прибавить множимое к

;старшему байту результата

noad80: ror m8uH ;сдвинуть вправо старший байт результата

ror m8uL ;сдвинуть вправо младший байт результата и ;множитель

brcc noad81 ;переход, если С=0

add m8uH,mc8u ;прибавить множимое к старшему ;байту ;результата

noad81: ror m8uH ;сдвинуть вправо старший байт результата

ror m8uL ;сдвинуть вправо младший байт ;результата и множитель

brcc noad82 ;переход, если С=0

add m8uH,mc8u ;прибавить множимое к старшему ;байту результата

noad82: ror m8uH ;сдвинуть вправо старший байт результата

ror m8uL ;сдвинуть вправо младший байт ;результата и множитель

brcc noad83 ;переход, если С=0

add m8uH,mc8u ;прибавить множимое к старшему ;байту результата

noad83: ror m8uH ;сдвинуть вправо старший байт результата

ror m8uL ;сдвинуть вправо младший байт ;результата и множитель

brcc noad84 ;переход, если С=0

add m8uH,mc8u ;прибавить множимое к старшему ;байту результата

noad84: ror m8uH ;сдвинуть вправо старший байт результата

ror m8uL ;сдвинуть вправо младший байт ;результата и множитель

brcc noad85 ;переход, если С=0

add m8uH,mc8u ;прибавить множимое к старшему ;байту результата

noad85: ror m8uH ;сдвинуть вправо старший байт результата

ror m8uL ;сдвинуть вправо младший байт ;результата и множитель

brcc noad86 ;переход, если С=0

add m8uH,mc8u ;прибавить множимое к старшему ;байту результата

noad86: ror m8uH ;сдвинуть вправо старший байт результата

ror m8uL ;сдвинуть вправо младший байт ;результата и множитель

brcc noad87 ;переход, если С=0

add m8uH,mc8u ;прибавить множимое к старшему ;байту результата

noad87: ror m8uH ; сдвинуть вправо старший байт результата

ror m8uL ; сдвинуть вправо младший байт ;результата и множитель

.exit ; конец программы

4.1.2 Умножение знаковых целых восьмиразрядных чисел (8х8=16)

Предлагаемая программа “mpy8s” реализует алгоритм Бута для умножения целых знаковых чисел, представленных в дополнительном коде, который обеспечивает как быстрое время исполнения, так и компактный код. Однако данный алгоритм имеет одно ограничение, о котором должен помнить программист. Алгоритм не работает, если множитель имеет минимально возможное значение “ –128” и требуется использовать все 16 разрядов результата. В соответствии с этим агоритмом определенным образом анализируются парные биты множителя, и в зависимости от их комбинации над множимым выполняются некоторые преобразования.

При реализации умножителей основную задержку в процесс формирования произведения вносит суммирование частичных произведений. Уменьшение их числа сокращает время суммирования

Непосредственное вычисление связано с вычислением частичных произведений вида. Число таких произведений равно разрядности множителей.

Программа “mpy8s” использует четыре регистра (табл. 4.4), имеет длину кода 8 слов и время исполнения 73 такта.

Таблица 4.4 Использование регистров программой "mpy8s"

Регистр

На входе программы

Внутри программы

На выходе программы

R16

“mc8s”-множимое

R17

“mp8s”-множитель

“m8sL” - младший байт результата

R18

“m8sH” - старший байт результата

R19

“mcnt8s”- счетчик цикла

Алгоритм программы "mpy8s" (рис. 4.3) включает в себя следующие шаги:

  1. Очистить старший байт результата и бит переноса С

  2. Инициализировать счетчик цикла значением 8

  3. Если бит переноса установлен, прибавить множимое к старшему байту результата.

  4. Если нулевой бит множителя установлен, вычесть множимое из старшего байта результата.

  5. Сдвинуть вправо старший байт результата с использованием переноса С

  6. Сдвинуть вправо младший байт результата/множитель.

  7. Уменьшить на 1 счетчик цикла

  8. Если счетчик цикла еще не равен 0 вернуться к шагу 3.

Если использовать обозначения (1), (2), то приведенный алгоритм можно представить в виде следующей формулы:

(4)

Рассмотрим отдельно два случая: при B > 0 и при B < 0.

В первом случае, когда B > 0 и, следовательно, старший бит множителя b7=0, формулу (4) можно записать:

(5)

Во втором случае, когда B < 0, имея в виду, что для представления операндов используется дополнительный код, можно записать

(6)

Таким образом, (5) и (6) показывают, что предлагаемый алгоритм действительно реализует операцию умножения двух знаковых целых чисел, представленных в дополнительном коде.

Рис. 4.3 Алгоритм программы “mpy8s” умножения 8-и разрядных целых знаковых чисел

Текст программы mpy8s умножения 8-и разрядных целых знаковых чисел (После запуска программы при помощи команды Run/Step into (F7) при очистке регистров множителя и множимого, необходимо занести значения множителя и множимого (в дополнительном коде) в эти регистры: в окне регистров (Alt+Shift+R) напротив значения регистров щелкнуть правой кнопкой мыши, установить десятичный формат, ввести значение).

Использование регистров

; ******************************************************

; BASIC .ASM template file for AVR

; ******************************************************

.include "C:\VMLAB\include\m128def.inc""; определение библиотеки МК ;ATmega128, при условии расположения программы VMLAB на

;локальном диске С

; Define here the variables

.def mc8s =r16 ;множимое

.def mp8s =r17 ;множитель

.def m8sL =r17 ;младший байт результата

.def m8sH =r18 ;старший байт результата

.def mcnt8s=r19 ;счетчик цикла

reset: ; начальная метка

rjmp start

reti ; Addr $01

reti ; Addr $02

reti ; Addr $03 Вектора прерываний МК ATmega128.

reti ; Addr $04 Приведены вектора с адреса $01 по адрес $10.

reti ; Addr $05 Полностью вектора прерываний представлены

reti ; Addr $06 в приложении с назначением прерываний

reti ; Addr $07 (внешних и внутренних).

reti ; Addr $08

reti ; Addr $09

reti ; Addr $0A

reti ; Addr $0B

reti ; Addr $0C

reti ; Addr $0D

reti ; Addr $0E

reti ; Addr $0F

reti ; Addr $10

start: ldi mc8s, A ;загрузить множимое

ldi mp8s, B ; загрузить множитель

mpy8s: sub m8sH,m8sH ; очистить старший байт результата и ;перенос

ldi mcnt8s,8 ; инициализировать счетчик цикла

m8s_1: brcc m8s_2 ; переход, если С=0

add m8sH,mc8s ; прибавить множимое к старшему

;байту результата

m8s_2: sbrc mp8s,0 ;если нулевой бит множителя установлен,

sub m8sH,mc8s ;вычесть множимое из старшего байта ;результата

asr m8sH ; сдвинуть вправо старший байт результата

ror m8sL ; сдвинуть вправо младший байт

;результата и множитель

dec mcnt8s ;уменьшить на 1 счетчик цикла

brne m8s_1 ; переход, если счетчик цикла не равен 0

.exit ; конец программы

4.2.3 Деление беззнаковых целых восьмиразрядных чисел (8/8=8+8)

Работа предлагаемых к использованию подпрограмм деления целых беззнаковых чисел основана на известном алгоритме деления в столбик. Для 8-ми и 16-ти разрядных чисел разработано соответственно по две подпрограммы, которые, как и подпрограммы умножения, различаются между собой тем, что оптимизированные по длине кода программы используют циклическое повторение операций, а программы, оптимизированные по времени исполнения, содержат последовательные повторяющиеся участки кода. В задании приведены тексты подпрограмм div8u_c и div8u_s для восьмиразрядных чисел. Ниже (табл. 4.5) представлены их основные параметры и используемые регистры (табл. 4.6). Видно, что для хранения результата деления используется тот же регистр, что и для хранения делителя. Так же, как и в подпрограммах умножения, такой прием позволяет уменьшить время исполнения подпрограмм, длину кода и количество используемых регистров.

Таблица 4.5 Подпрограммы деления целых беззнаковых восьмиразрядных чисел

Название

программы

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

Длина кода, слов

Время исполнения, такты

div8u_c

Беззнаковое деление

8/8=8+8 Оптимизация кода.

14

97

div8u_s

Беззнаковое деление

8/8=8+8 Оптимизация времени исполнения..

66

58

Таблица 4.6 Использование регистров программой"div8u_с"

Регистр

На входе программы

Внутри программы

На выходе программы

R15

“drem8u” - остаток

R16

“dd8u”-делимое

“dres8u” - результат

R17

“dv8u”-делитель

R18

“dcnt8u”- счетчик цикла

Алгоритм подпрограмм деления целых беззнаковых чисел (рис. 4.4) можно представить в виде последовательности следующих шагов:

  1. Очистить остаток и перенос

  2. Загрузить в счетчик цикла число 9

  3. Делимое сдвинуть влево с использованием переноса.

  4. Уменьшить на 1 счетчик цикла

  5. Если счетчик цикла равен 0, то выйти из подпрограммы

  6. Остаток сдвинуть влево с использованием переноса

  7. Вычесть делитель из остатка

  8. Если остаток отрицательный, прибавить обратно делитель, сбросить перенос и идти к шагу 3.

  9. Установить перенос и идти к шагу 3.

Рис. 4.4 Алгоритм программы "div8u_с" деления целых беззнаковых восьмиразрядных чисел

Текст программы div8u_с деления 8-и разрядных целых беззнаковых чисел, оптимизированной с точки зрения длины кода. (После запуска программы при помощи команды Run/Step into (F7) при очистке регистров делителя и делимого, необходимо занести значения делителя и делимого в эти регистры: в окне регистров (Alt+Shift+R) напротив значения регистров щелкнуть правой кнопкой мыши, установить десятичный формат, ввести значение).

Использование регистров (инициализация переменных)

; ******************************************************

; BASIC .ASM template file for AVR

; ******************************************************

.include "C:\VMLAB\include\m128def.inc""; определение библиотеки МК ;ATmega128, при условии расположения программы VMLAB на

;локальном диске С

; Define here the variables

.def drem8u=r15 ;остаток

.def dres8u=r16 ;результат

.def dd8u =r16 ;делимое

.def dv8u =r17 ;делитель

.def dcnt8u=r18 ;счетчик цикла

reset: ; начальная метка

rjmp start

reti ; Addr $01

reti ; Addr $02

reti ; Addr $03 Вектора прерываний МК ATmega128.

reti ; Addr $04 Приведены вектора с адреса $01 по адрес $10.

reti ; Addr $05 Полностью вектора прерываний представлены

reti ; Addr $06 в приложении с назначением прерываний

reti ; Addr $07 (внешних и внутренних).

reti ; Addr $08

reti ; Addr $09

reti ; Addr $0A

reti ; Addr $0B

reti ; Addr $0C

reti ; Addr $0D

reti ; Addr $0E

reti ; Addr $0F

reti ; Addr $10

start: ldi dd8u, A ; загрузить делимое

ldi dv8u, B ; загрузить делитель

div8u_c: sub drem8u,drem8u ;очистить остаток и перенос

ldi dcnt8u,9 ;инициализировать счетчик цикла

d8u_1: rol dd8u ;делимое/результат сдвинуть влево

dec dcnt8u ;уменьшить на единицу счетчик цикла

brne d8u_2 ;переход, если не ноль

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

d8u_2: rol drem8u ;остаток сдвинуть влево

sub drem8u,dv8u ;остаток = остаток - делитель

brcc d8u_3 ;если результат < 0

add drem8u,dv8u ;восстановить остаток

clc ;сбросить перенос для

;формирования результата

rjmp d8u_1 ;иначе

d8u_3: sec ;установить перенос для формирования результата

rjmp d8u_1 ;вернуться назад

Примечание: А – числовое значение делимого, В – числовое значение делителя.

Рис. 4.5 Алгоритм программы "div8u_s" деления целых беззнаковых восьмиразрядных чисел

Текст программы div8u_s деления 8-и разрядных целых беззнаковых чисел, оптимизированной с точки зрения времени исполнения. (После запуска программы при помощи команды Run/Step into (F7) при очистке регистров делителя и делимого, необходимо занести значения делителя и делимого в эти регистры: в окне регистров (Alt+Shift+R) напротив значения регистров щелкнуть правой кнопкой мыши, установить десятичный формат, ввести значение). Алгоритм программы представлен на рис. 4.5.

Использование регистров (инициализация переменных)

; ******************************************************

; BASIC .ASM template file for AVR

; ******************************************************

.include "C:\VMLAB\include\m128def.inc""; определение библиотеки МК ;ATmega128, при условии расположения программы VMLAB на

;локальном диске С

; Define here the variables

.def drem8u=r15 ;остаток

.def dres8u=r16 ;результат

.def dd8u =r16 ;делимое

.def dv8u =r17 ;делитель

reset: ; начальная метка

rjmp start

reti ; Addr $01

reti ; Addr $02

reti ; Addr $03 Вектора прерываний МК ATmega128.

reti ; Addr $04 Приведены вектора с адреса $01 по адрес $10.

reti ; Addr $05 Полностью вектора прерываний представлены

reti ; Addr $06 в приложении с назначением прерываний

reti ; Addr $07 (внешних и внутренних).

reti ; Addr $08

reti ; Addr $09

reti ; Addr $0A

reti ; Addr $0B

reti ; Addr $0C

reti ; Addr $0D

reti ; Addr $0E

reti ; Addr $0F

reti ; Addr $10

start: ldi dd8u, A ; загрузить делимое

ldi dv8u, B ; загрузить делитель

div8u_s: sub drem8u,drem8u ; очистить остаток и перенос

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

rol drem8u ; остаток сдвинуть влево

sub drem8u,dv8u ; остаток= остаток - делитель

brcc d8u_1 ; если результат < 0

add drem8u,dv8u ; восстановить остаток

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

rjmp d8u_2 ;иначе

d8u_1: sec ; установить перенос для формирования результата

d8u_2: rol dd8u ;делимое/результат сдвинуть влево

rol drem8u ; остаток сдвинуть влево

sub drem8u,dv8u ; остаток= остаток - делитель

brcc d8u_3 ; если результат < 0

add drem8u,dv8u ; восстановить остаток

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

rjmp d8u_4 ;иначе

d8u_3: sec ; установить перенос для формирования результата

d8u_4: rol dd8u ;делимое/результат сдвинуть влево

rol drem8u ; остаток сдвинуть влево

sub drem8u,dv8u ; остаток= остаток - делитель

brcc d8u_5 ; если результат < 0

add drem8u,dv8u ; восстановить остаток

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

rjmp d8u_6 ;иначе

d8u_5: sec ;установить перенос для формирования результата

d8u_6: rol dd8u ;делимое/результат сдвинуть влево

rol drem8u ; остаток сдвинуть влево

sub drem8u,dv8u ; остаток= остаток - делитель

brcc d8u_7 ; если результат < 0

add drem8u,dv8u ; восстановить остаток

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

rjmp d8u_8 ;иначе

d8u_7: sec ; установить перенос для формирования результата

d8u_8: rol dd8u ;делимое/результат сдвинуть влево

rol drem8u ; остаток сдвинуть влево

sub drem8u,dv8u ; остаток= остаток - делитель

brcc d8u_9 ; если результат < 0

add drem8u,dv8u ; восстановить остаток

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

rjmp d8u_10 ;иначе

d8u_9: sec ;установить перенос для формирования результата

d8u_10: rol dd8u ;делимое/результат сдвинуть влево

rol drem8u ; остаток сдвинуть влево

sub drem8u,dv8u ; остаток= остаток - делитель

brcc d8u_11 ; если результат < 0

add drem8u,dv8u ; восстановить остаток

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

rjmp d8u_12 ;иначе

d8u_11: sec ; установить перенос для формирования результата

d8u_12: rol dd8u ;делимое/результат сдвинуть влево

rol drem8u ; остаток сдвинуть влево

sub drem8u,dv8u ; остаток= остаток - делитель

brcc d8u_13 ; если результат < 0

add drem8u,dv8u ; восстановить остаток

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

rjmp d8u_14 ;иначе

d8u_13: sec ; установить перенос для формирования результата

d8u_14: rol dd8u ;делимое/результат сдвинуть влево

rol drem8u ; остаток сдвинуть влево

sub drem8u,dv8u ; остаток= остаток - делитель

brcc d8u_15 ; если результат < 0

add drem8u,dv8u ; восстановить остаток

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

rjmp d8u_16 ; иначе

d8u_15: sec ; установить перенос для формирования результата

d8u_16: rol dd8u ;делимое/результат сдвинуть влево

.exit ; конец программы

4.2.4 Деление знаковых целых восьмиразрядных чисел (8/8=8+8)

Для деления знаковых целых чисел, представленных в дополнительном коде, предлагается программа div8s, текст которой приведен ниже. Эта программа так же, как и предыдущая реализует алгоритм деления в столбик. Поэтому ее отличие от программы div8u заключается лишь в том, что предварительно вычисляются модули двух операндов и в дополнительном регистре сохраняется информация о знаке результата, который учитывается после выполнения деления перед выходом из подпрограммы. Использование регистров программой div8s представлено в таблице 4.7.

Таблица 4.7 Использование регистров программой"div8s"

Регистр

На входе программы

Внутри программы

На выходе программы

R14

“d8s”- регистр знака

R15

“drem8u” - остаток

R16

“dd8u”-делимое

“dres8u” - результат

R17

“dv8u”-делитель

R18

“dcnt8u”- счетчик цикла

Рис. 4.6 Алгоритм программы "div8s" деления целых знаковых восьмиразрядных чисел

Текст программы div8s деления 8-и разрядных целых знаковых чисел, оптимизированной с точки зрения времени исполнения. (После запуска программы при помощи команды Run/Step into (F7) при очистке регистров делителя и делимого, необходимо занести значения делителя и делимого (в дополнительном коде) в эти регистры: в окне регистров (Alt+Shift+R) напротив значения регистров щелкнуть правой кнопкой мыши, установить десятичный формат, ввести значение). Алгоритм программы представлен на рис. 4.6.

Использование регистров (инициализация переменных)

; ******************************************************

; BASIC .ASM template file for AVR

; ******************************************************

.include "C:\VMLAB\include\m128def.inc""; определение библиотеки МК ;ATmega128, при условии расположения программы VMLAB на

;локальном диске С

; Define here the variables

.def d8s =r14 ;регистр знака

.def drem8s=r15 ;остаток

.def dres8s=r16 ;результат

.def dd8s =r16 ;делимое

.def dv8s =r17 ;делитель

.def dcnt8s=r18 ;счетчик цикла

reset: ; начальная метка

rjmp start

reti ; Addr $01

reti ; Addr $02

reti ; Addr $03 Вектора прерываний МК ATmega128.

reti ; Addr $04 Приведены вектора с адреса $01 по адрес $10.

reti ; Addr $05 Полностью вектора прерываний представлены

reti ; Addr $06 в приложении с назначением прерываний

reti ; Addr $07 (внешних и внутренних).

reti ; Addr $08

reti ; Addr $09

reti ; Addr $0A

reti ; Addr $0B

reti ; Addr $0C

reti ; Addr $0D

reti ; Addr $0E

reti ; Addr $0F

reti ; Addr $10

start: ldi dd8s, A ;загрузить делимое

ldi dv8s, B ;загрузить делитель

div8s: mov d8s,dd8s ;переслать делимое в регистр знака

eor d8s,dv8s ;xor регистра знака и делителя

sbrc dv8s,7 ;если MSB делителя установлен neg dv8s ; изменить знак делителя

sbrc dd8s,7 ;если MSB делимого установлен

neg dd8s ; изменить знак делимого

sub drem8s,drem8s ;очистить остаток и перенос

ldi dcnt8s,9 ;инициализировать счетчик цикла

d8s_1: rol dd8s ;делимое сдвинуть влево

dec dcnt8s ;декремент счетчика

brne d8s_2 ;если счетчик цикла равен нулю

sbrc d8s,7 ;если MSB регистра знака

neg dres8s ;изменить знак результата

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

d8s_2: rol drem8s ;сдвинуть остаток влево

sub drem8s,dv8s ;остаток = остаток - делитель

brcc d8s_3 ;если результат отрицательный

add drem8s,dv8s ;восстановить остаток

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

rjmp d8s_1 ;иначе

d8s_3: sec ;установить перенос для формирования результата

rjmp d8s_1

Листинг проектного файла №4

.MICRO " ATmega128" ;Указание типа микроконтроллера (ATmega128)

.PROGRAM " Project4.asm" ; Ассемблируемый файл

.TARGET " Project4.hex" ; Файл машинного кода

.TRACE ; Включение трассировки

.POWER VDD=5 VSS=0 ; Задание напряжения питания 5 В

.CLOCK 4meg ; Задание тактовой частоты работы микроконтроллера

.STORE 250m ; Время регенерации сигнала осциллографа

Соседние файлы в папке Новая папка (1)