Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Подпрограмму перемножения двух таких величин, представленных в исходном 16-разрядном виде, с представлением результата в трехбайтовой форме можно легко получить из исправленной нами процедуры MPY16U по "аппноте" 200 (пример см. в главе 10). Но здесь я решил воспользоваться тем обстоятельством, что для контроллеров семейства Mega определены аппаратные операции умножения (в приложении 2 они не приведены). Тогда алгоритм сильно упрощается, причем он легко модифицируется как для 32-, так и для 24-разрядного результата. Таким образом, для Tiny и Classic по-прежнему следует пользоваться обычными процедурами из "аппноты" (исправленными), а для Mega мы будем использовать алгоритм, приведенный в листинге 7.3 (в названиях исходных переменных отражен факт основного назначения такой процедуры — для умножения неких данных на некий коэффициент, некоторые комментарии сохранены из английского текста "аппноты").

Листинг 7.3
.def dataL = r4 /multiplicand low byte .def dataH = r5 ;multiplicand high byte •def KoeffL = r2 /multiplier low byte .def koe'ffH = r3 /multiplier high byte .def temp = rl6 /result byte 0 (LSD1) .def temp2 = rl7 /result byte 1 .def temp3 = rl8 /result byte 2 (MSD)

/умножение двух 16-разрядных величин, только для Меда /исходные величины
dataH:dataL и KoeffH:KoeffL /результат 3 байта temp2:tempi:temp
Mul616:
clr temp2 /очистить старший
mul dataL,KoeffL /умножаем младшие
mov temp,гО /в гО младший результата операции mul
mov tempi,rl /в rl старший результата операции mul
mul dataH,KoeffL /умножаем старший на младший
add tempi,гО /в гО младший результата операции mul
adc temp2,rl /в rl старший результата операции mul
mul dataL,KoeffH /умножаем младший на старший
LSD (MSD) — least (most) significant digit, младшая (старшая) значащая цифра.
В дальнейшем нам встретятся также LSB и MSB, означающие least (most) significant bit — младший (старший) значащий разряд, по-русски МЗР и СЗР соответственно.

add tempi,гО ;в гО младший результата операции mul
adc temp2,rl ;в rl старший результата операции mul
mul dataH,KoeffH /умножаем старший на старший
add temp2,r0 ;4-й разряд нам тут не требуется, но он — в г01
ret

Как видите, эта процедура легко модифицируется для любой разрядности результата — если нужно получить полный 32-разрядный диапазон, просто добавьте еще один регистр для старшего разряда (temp3, к примеру) и одну строку кода перед командой ret: adc temp3,rl
Естественно, можно просто обозначить rl через temp3, тогда и добавлять ничего не придется.

Деление многоразрядных чисел

Самый простой алгоритм деления — определить, сколько раз можно вычесть делитель из делимого, однако в фирменных "аппнотах" он выглядит несколько сложнее. Деление — значительно более громоздкая процедура, чем умножение, требует больше регистров и времени (MPY16U ИЗ "аппноты" занимает 153 такта, по уверению разработчиков, а аналогичная операция деления двух 16-разрядных чисел — от 235 до 251).
Операции деления двух чисел (и 8-, и 16-разрядных) приведены в той же "аппноте" 200, и на этот раз без ошибок, но они не всегда удобны на практике: часто нам приходится делить результат какой-то ранее проведенной операции умножения или сложения, а он нередко выходит за пределы двух байтов.

Поэтому пришлось разрабатывать свои операции. Например, часто встречается необходимость вычислить среднее значение для уточнения результата по сумме отдельных измерений. Если даже само измерение укладывается в 16 разрядов, то сумма нескольких таких результатов уже должна занимать три или четыре байта. В то же время делитель — число измерений — может быть и относительно небольшим, и укладываться в один байт. Здесь я привожу процедуру деления 32-разрядных чисел на однобайтовое число, которая представляет собой модификацию оригинальной процедуры из Application notes 200 (листинг 7.4). Названия переменных отражают назначение процедуры — деление состояния некоего 4-байтового счетчика на число циклов счета (определения регистров-переменных не приводятся, комментарии сохранены из оригинального текста "аппноты", они соответствуют блок-схеме алгоритма, размещенной в PDF-файле).

;div32x8 — 32/8 деление беззнаковых чисел
;Делимое и результат в count_HH (старший), countTH,
;countTM, countTL (младший)
;делитель в cikle
;требуется четыре рабочих регистра dremL — dremHH /из диапазона г16-г31 для хранения остатка
div32x8:
clr dremL ;clear remainder Low byte clr dremM ;clear remainder clr dremH ;clear remainder
sub dremHH,dremHH ;clear remainder High byte and carry
ldi cnt,33 ;init loop counter
d_l: rol countTL ;shift left dividend
rol countTM
rol countTH rol count_HH dec cnt /decrement counter brne d_2 ;if done ret ;return
d_2: rol dremL /shift dividend into remainder
rol dremM rol dremH rol dremHH
sub dremL,cikle /remainder = remainder — divisor
sbci dremM, 0 /
sbci dremH, 0 /
sbci dremHH, 0 /
brcc d_3 /if result negative
add dremL, cikle /restore remainder
clr temp
adc dremM, temp adc dremH, temp adc dremHH, temp
clc /clear carry to be shifted into result
rjmp d_l /else
d_3: sec /set carry to be shifted into result
rjmp d_l .*********** **** ***** *конец 32x8

Отдав таким образом дань профессионализму программистов Atmel, заметим, что эта подпрограмма достаточно громоздка и построена по довольно "мутному" алгоритму. Процедуру деления можно значительно упростить (хотя в среднем она будет выполняться заметно медленнее), реализовав впрямую упомянутый ранее алгоритм подсчета числа вычитаний делителя из делимого. Код программы содержит листинг 7.5 (регистры countxx и cykie здесь означают то же самое, что и в листинге 7.4, результат же окажется в регистрах resultHH — resultTL).

clr resultTL clr resultTM clr resultTH clr resultHH div32x8:
sub dountTL,cykle
sbc countTM,0
sbc countTH, 0
sbc countHH, 0
brcs end_div32x8 ;если перенос в минус, то на выход
inc resultTL ;иначе увеличиваем результат на 1 — младший байт
brne div32x8 /если не было переноса, то обратно
inc resultTM /иначе следующий байт на 1
brne div32x8 /если не было переноса, то обратно
inc resultTH /иначе следующий байт на 1
brne div32x8 /если не было переноса, то обратно
inc resultHH /иначе старший байт на 1 rjmp div32x8 /обратно end_div32x8:
;==конец процедуры div32x8



     
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru