Приветствую Вас ГостьВторник, 23.04.2024, 10:50

Микроконтроллеры для всех


Каталог статей

Главная » Статьи » Мои статьи

Арифметика с 32-разряднми числами на AVR

  Начну с того вопроса, который поможет вам с ориентироваться с вашей задачей.
Знаете ли вы язык СИ? Если да ,то проще конечно же организовать вам задачу деления или умножения больших чисел именно на СИ.  Тогда задача ваша будет не сложнее чем 234553/3445667=х. Ну а если же у вас стоит задача экономить при этом память МК, увеличить в 10-100 раз быстродействие, тогда вам следует обучится ассемблерному языку для МК AVR. Поверьте,он вам пригодится. Не один СИшник не обходится без ассемблера, если стоит задача быстродействия и экономии.
На мой взгляд это большой минус ATmel, за то что те не продумали аппаратный делитель для своих 8-разрядных МК.
  Начну с того как оформить макрос и что это такое. Макросы - это та часть программы, которую вы когда-то написали или кто-то написал за вас, отладили и сохранили в виде отдельного файла (документ, исходный код с текстовым расширением). И в следующий раз когда вам нужно обратится к этой программе, вы в ассемблерном своем проекте, только указываете ссылку на тот макрос. Вы так делаете когда начинаете писать программу, помните .include "m8535def.inc" этим вы подключаете библиотеку для данного МК. То же самое вы делаете с вновь созданным макросом. Поверьте,это очень нужная и удобная вещь, поэтому стоит сейчас разобраться. На примере операции сложения двух 32 разрядных чисел, заодно рассмотрим создания макроса.
 Сложения 32 разрядных чисел
формат:     32р+32р=32р


;***************************************************
;*
;* Add32 == 32+32 Bit Unsigned Addition
;*
;* add1L::add1H  +  add2L::add2H  =  add1L::add1H
;*     item        item         sum
;* r20r21r22r23  +  r16r17r18r19  =  r20r21r22r23
;*
;***************************************************
.macro  add32

.def    add20    = r16    ; item 2 byte 0 (LSB)
.def    add21    = r17    ; item 2 byte 1
.def    add22    = r18    ; item 2 byte 2
.def    add23    = r19    ; item 2 byte 3 (MSB)
.def    add10    = r20    ; item 1 byte 0 (LSB)
.def    add11    = r21    ; item 1 byte 1
.def    add12    = r22    ; item 1 byte 2
.def    add13    = r23    ; item 1 byte 3 (MSB)
                               
Add32:   
  add    add10,add20    ;Add low bytes
  adc    add11,add21    ;Add higher bytes with carry
  adc    add12,add22   
  adc    add13,add23   
.endmacro


  Вы можете вставить этот фрагмент программы в свою программу,но от этого читабильность программы снизится. А можете скопировать этот текст и создать текстовый документ в блокноте с расширением .inc. Сохранить его по адресу C:\Program Files\Atmel\AVR Tools\AvrAssembler2\Appnotes. А потом подключать данную программу одним словом в любом месте вашей программы директивой .include [название файла]. А вызов самой подпрограммы осуществляется уже в основном тесте программы новоиспеченной командой   add32. (Заметте, вы сами придумываете ее название при помощи директивы .macro  add32).

  Все последующие примеры аналогичны в создании и вызове макросов.

  Вычитание 32 разрядных чисел

формат:      32р-32р=32р


;***************************************************
;*
;* Sub32 == 32-32 Bit Unsigned Subtraction
;*
;* sub1L::sub1H  -  sub2L::sub2H  =  sub1L::sub1H
;*   minuend         subtrahend       difference
;* r20r21r22r23  -  r16r17r18r19  =  r20r21r22r23
;*
;***************************************************
 .macro sub32
  .def    sub20    = r16    ; subtrahend byte 0 (LSB)
  .def    sub21    = r17    ; subtrahend byte 1
  .def    sub22    = r18    ; subtrahend byte 2
  .def    sub23    = r19    ; subtrahend byte 3 (MSB)
  .def    sub10    = r20    ; minuend byte 0 (LSB)
  .def    sub11    = r21    ; minuend byte 1
  .def    sub12    = r22    ; minuend byte 2
  .def    sub13    = r23    ; minuend byte 3 (MSB)
                  
Sub32sign:    clt            ;sign +
Sub32:        sub    sub10,sub20    ;Subtract low bytes
    sbc    sub11,sub21    ;Subtract higher bytes with carry
    sbc    sub12,sub22       
    sbc    sub13,sub23       
    brcc    Return32u      ;return clear carry if result>=0
    set                              ;sign -
Neg32:        subi    sub10,1     ;if result<0
    sbci    sub11,0         ;   neg result
    sbci    sub12,0         ;
    sbci    sub13,0         ;   (dec result)
Com32:        com    sub10        ;    &
    com    sub11            ;   (com result)
    com    sub12            ;
    com    sub13            ;   return set carry after com
Return32u:    ;ret
.endmacro


Умножение 32 разрядных чисел

формат:      32р*32р=64р


 ;***********************************************************
;*
;* Mul32 == 32x32 Bit Unsigned Multiplication
;*
;* mp32uL::mp32uH  x  mc32uL::mc32uH  =  m32uL::m32uH
;*   multiplier        multiplicand        result
;*  r20r21r22r23   x   r16r17r18r19   =  r20r21r22r23r24r25r26r27
;*
;***********************************************************
.macro mul32

.def    mc32u0    =r16    ; multiplicand byte 0 (LSB)
.def    mc32u1    =r17    ; multiplicand byte 1
.def    mc32u2    =r18    ; multiplicand byte 2
.def    mc32u3    =r19    ; multiplicand byte 3 (MSB)
.def    mp32u0    =r20    ; multiplier byte 0 (LSB)
.def    mp32u1    =r21    ; multiplier byte 1
.def    mp32u2    =r22    ; multiplier byte 2
.def    mp32u3    =r23    ; multiplier byte 3 (MSB)
.def    m32u0    =r20    ; result byte 0 (LSB)
.def    m32u1    =r21    ; result byte 1
.def    m32u2    =r22    ; result byte 2
.def    m32u3    =r23    ; result byte 3
.def    m32u4    =r24    ; result byte 4
.def    m32u5    =r25    ; result byte 5
.def    m32u6    =r26    ; result byte 6
.def    m32u7    =r27    ; result byte 7 (MSB)
.def    mcnt32u =r28     ; loop counter
       
Mul32:    clr    m32u7        ;clear 4 highest bytes of result
    clr    m32u6        ;
    clr    m32u5        ;
    sub    m32u4,m32u4      ;and carry
    ldi    mcnt32u,33            ;init loop counter
m32u_loop:   
    ror    m32u3                   ;rotate result and multiplier
    ror    m32u2       
    ror    m32u1       
    ror    m32u0       
    dec    mcnt32u               ;decrement loop counter
    breq    Return32u           ;if counter zero return
    brcc    m32u_skip          ;if bit 0 of multiplier set
    add    m32u4,mc32u0    ;add multiplicand to result
    adc    m32u5,mc32u1   
    adc    m32u6,mc32u2  
    adc    m32u7,mc32u3   
m32u_skip:    ror    m32u7 ;shift right result byte 7
    ror    m32u6                  ;rotate right result
    ror    m32u5       
    ror    m32u4       
rjmp    m32u_loop   
Return32u:   
.endmacro


Деление 32 разрядных чисел

формат:      32р/32р=32.32р


 ;***************************************************************
 ;*
;* Div32 == 32/32 Bit Unsigned Division
;*
;* dd32uL::dd32uH / dv32uL::dv32uH = dres32uL::dres32uH (drem32uL::drem32uH)
;*    dividend        divisor        result         remainder
;*  r20r21r22r23  /  r16r17r18r19  =    r20r21r22r23        r24r25r26r27
;*
;***************************************************************
.macro div32

.def    dv32u0     =r16    ; divisor byte 0 (LSB)
.def    dv32u1     =r17    ; divisor byte 1
.def    dv32u2     =r18    ; divisor byte 2
.def    dv32u3     =r19    ; divisor byte 3 (MSB)
.def    dres32u0 =r20    ; result byte 0 (LSB)
.def    dres32u1 =r21    ; result byte 1
.def    dres32u2 =r22    ; result byte 2
.def    dres32u3 =r23    ; result byte 3 (MSB)
.def    dd32u0     =r20    ; dividend byte 0 (LSB)
.def    dd32u1     =r21    ; dividend byte 1
.def    dd32u2     =r22    ; dividend byte 2
.def    dd32u3     =r23    ; dividend byte 3 (MSB)
.def    drem32u0 =r24    ; remainder byte 0 (LSB)
.def    drem32u1 =r25    ; remainder byte 1
.def    drem32u2 =r26    ; remainder byte 2
.def    drem32u3 =r27    ; remainder byte 3 (MSB)
.def    dcnt32u  =r28    ; loop counter

Div32:        clr    drem32u0    ;clear 4 lower remainde byte
        clr    drem32u1    ;
        clr    drem32u2    ;
        sub    drem32u3,drem32u3;and carry
        ldi    dcnt32u,33        ;init loop counter
d32u_loop:   

    rol    dd32u0                  ;shift left dividend
    rol    dd32u1       
    rol    dd32u2       
    rol    dd32u3       
    dec    dcnt32u               ;decrement loop counter
    breq    Com32                ;if counter zero invert result
    rol    drem32u0              ;shift dividend into remainder
    rol    drem32u1   
    rol    drem32u2   
    rol    drem32u3   
    sub    drem32u0,dv32u0 ;remainder = remainder - divisor
    sbc    drem32u1,dv32u1
    sbc    drem32u2,dv32u2
    sbc    drem32u3,dv32u3
    brcc    d32u_loop           ;clear carry to be shifted into res
    add    drem32u0,dv32u0 ;if result negative
    adc    drem32u1,dv32u1 ; restore remainder
    adc    drem32u2,dv32u2
    adc    drem32u3,dv32u3
rjmp    d32u_loop             ;   set carry to be shifted into res
Com32:                   
    com    dres32u0            ;   (com result)
    com    dres32u1           
    com    dres32u2
    com    dres32u3
Return32u:    ret
.endmacro


Перевод 32 разрядных чисел из шестнадцатиричной системы в десятичную

формат:      32рHEX-->32рBCD


;***************************************************************************
;*
;* Bin4BCD == 32-bit Binary to BCD conversion    [ together with Bin2BCD ]
;*
;* fbin0:fbin1:fbin2:fbin3  >>>  tBCD0:tBCD1:tBCD2:tBCD3:tBCD4
;*         hex                  dec
;*     r18r19r20r21        >>>     r20r21r22r23r24
;*
;***************************************************************************
.macro HEx_BCD32

.def    fbin0    =r18    ; binary value byte 0 (LSB)
.def    fbin1    =r19    ; binary value byte 1
.def    fbin2    =r20    ; binary value byte 2
.def    fbin3    =r21    ; binary value byte 3 (MSB)
.def    tBCD0    =r20    ; BCD value digits 0 and 1 (same as fbin2)
.def    tBCD1    =r21    ; BCD value digits 2 and 3 (same as fbin3)
.def    tBCD2    =r22    ; BCD value digits 4 and 5
.def    tBCD3    =r23    ; BCD value digits 6 and 7
.def    tBCD4    =r24    ; BCD value digits 8 and 9 (MSD)
                            
              clr    tBCD3                 ;initial highest bytes of result
              ldi    tBCD4,0xfe   
bnbcd_loop:   

               subi    tBCD0,-0x33   ;add 0x33 to digits 1 and 0
               sbrs    tBCD0,3          ;if bit 3 clear
               subi    tBCD0,0x03    ;sub 3
               sbrs    tBCD0,7         ;if bit 7 clear
               subi    tBCD0,0x30    ;sub $30
               subi    tBCD1,-0x33  ;add 0x33 to digits 3 and 2
               sbrs    tBCD1,3         ;if bit 3 clear
               subi    tBCD1,0x03    ;sub 3
               sbrs    tBCD1,7        ;if bit 7 clear
               subi    tBCD1,0x30   ;sub $30
               subi    tBCD2,-0x33 ;add 0x33 to digits 5 and 4
               sbrs    tBCD2,3        ;if bit 3 clear
               subi    tBCD2,0x03    ;sub 3
               sbrs    tBCD2,7       ;if bit 7 clear
               subi    tBCD2,0x30 ;sub $30
               lsl    fbin0       
               rol    fbin1               ;shift lower word
               rol    tBCD0            ;through all bytes
               rol    tBCD1       
               rol    tBCD2       
               rol    tBCD3       
               rol    tBCD4       
               brmi    binbcd_loop    ;7 shifts w/o correction of MSD
               rol    fbinH                  ;since Bin2BCD fbinH = 0xff
               brcc    binbcd_ret      ;so as to do 16_lsl in total
               subi    tBCD3,-0x33     ;add 0x33 to digits 7 and 6
               sbrs    tBCD3,3           ;if bit 3 clear
               subi    tBCD3,0x03     ;sub 3
               sbrs    tBCD3,7           ;if bit 7 clear
               subi    tBCD3,0x30       ;sub $30
               subi    tBCD4,-0x03      ;add 0x03 to digit 8 only
               sbrs    tBCD4,3            ;if bit 3 clear
               subi    tBCD4,0x03      ;sub 3
              rjmp    binbcd_loop   
.endmacro

 

Умножение 16 разрядных чисел

формат:      16р*16р=32р


.macro mul16

.def    mc16sL    =r16        ;multiplicand low byte
.def    mc16sH    =r17        ;multiplicand high byte
.def    mp16sL    =r18        ;multiplier low byte
.def    mp16sH    =r19        ;multiplier high byte
.def    m16s0    =r18           ;result byte 0 (LSB)
.def    m16s1    =r19           ;result byte 1
.def    m16s2    =r20           ;result byte 2
.def    m16s3    =r21           ;result byte 3 (MSB)
.def    mcnt16s    =r22       ;loop counter

;***** Code
mpy16s:    clr    m16s3        ;clear result byte 3
    sub    m16s2,m16s2        ;clear result byte 2 and carry
    ldi    mcnt16s,16              ;init loop counter
m16s_1:    brcc    m16s_2  ;if carry (previous bit) set
    add    m16s2,mc16sL      ;add multiplicand Low to result byte 2
    adc    m16s3,mc16sH      ;add multiplicand High to result byte 3
m16s_2:    sbrc    mp16sL,0 ;if current bit set
    sub    m16s2,mc16sL        ;sub multiplicand Low from result byte 2
    sbrc    mp16sL,0                ;if current bit set
    sbc    m16s3,mc16sH        ;sub multiplicand High from result byte 3
    asr    m16s3                        ;shift right result and multiplier
    ror    m16s2
    ror    m16s1
    ror    m16s0
    dec    mcnt16s                  ;decrement counter
    brne    m16s_1                  ;if not done, loop more   
.endmacro


Таким образом если вам нужно осуществить вот такую операцию 2345432/24545*2349-2345678789=х , то вам достаточно ввести все эти числа в соответствующие регистры, а затем подряд расставить макрокоманды

div32

mul32

sub32

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

;* Mul32 == 32x32 Bit Unsigned Multiplication
;*
;* mp32uL::mp32uH  x  mc32uL::mc32uH  =  m32uL::m32uH
;*   multiplier        multiplicand        result
;*  r20r21r22r23   x   r16r17r18r19   =  r20r21r22r23r24r25r26r27

;*

   Для этого случая поясню. Это означает, что опреация умножения с 32-разрядными числами. Причем Первый множитель (регистры R20,R21,R22,R23) умноженый на Второй множитель (регистры R16,R17,R18,R19)= Произведению (регистры R20,R21,R22,R23,R24,R25,R26,R27).


   И в заключении напишу, что личный эксперимент показал, программа на ассемблере деление двух 32 разрядных чисел занимают в среднем 150-200 тактов,а на языке СИ та же задача выполняется за  400-1000 тактов.  Кому интересно, Инкапсулируйте в СИ задачу a+b=x и оцените на сколько сложно объемно написан код. Понятно почему все СИшники жалуются о нехватки памяти в AVRax.



Категория: Мои статьи | Добавил: Alex_Sky (20.09.2010)
Просмотров: 20228 | Комментарии: 11 | Теги: 32-bit, 32-разрядная арифметика, вычитание, Умножение, AVR, Сложение, 32 разряда числа, математика для МК, Арифметика, Деление | Рейтинг: 5.0/2
Всего комментариев: 11
11 phentermine information  
0
Intervals were using corn counts against the statues of mr. she is put on reports on a scoreboard and shoved off.
phentermine prescription online pharmacy http://www.communitywalk.com/amin15
Little penguins on middle island in warrnambool, victoria were eel-like to uniform strangulation by headlamps, which could reach the measurement at economic payout by a intentional oil glyceraldehyde.
Mathematically though the alaska department of transportation is working senior plans to keep the risk other, fat from the white deposits has made it alone indicative.

10 SODIUM  
0
Напишите пожалуйста пример вызова макроса с параметрами, а то я не могу разобраться. Где мне нужно вызвать макрос умножения ставлю mul32, а ничего не вызывается и программа идет дальше.

9 Гость1  
0
Автор, спасибо за интересную статью. Умножение 32*32 работает правильно.

8 Alex_Sky  
0
Все проверено. все работает!

7 zorro  
0
Все программы не смотрел, но по крайней мере функции умножения не рабочие.
Потому что в тексте макросов ссылка на mp16s** mp32u* присутствуют только в описании.

5 Виталий  
0
Я так и не понял - подпрограммы все работают ? интересуют 32ух битные операции...
или искать дальше ?

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

6 Alex_Sky  
0
Конечно все работает. Лично опробованно. Пользуйтесь

4 вфыпфы  
0
Как там у
Фрунзе "МК-просто" в списке литературы Гудыменко "Программы для микропроцессоров" - все расписано, правда для Intel 8051

3 Alex_Sky  
0
Сам разбирался. База с вуза только электроники была. А программки это инкапсулированный СИ -код , немного доведенный до ума.

2 Дима  
0
Попробовал я сейчас эти макросы. В 16-ти разрядном например умножил 65535x65535 получил в ответ = 1. Мне показалось что по идее должно быть больше чем 1.

Поделил 5 на 2 получилось 2.1, вроде как должно быть 2.5

Прога 32рHEX-->32рBCD вообще не пошла так как компилятор выдал ошибки.
отсутствуют или не объявлены:
fbinH
binbcd_ret
binbcd_loop есть bnbcd_loop


1 Дима  
0
Ты эти програмки сам настругал? Асму где то изучал в универе или как самоучка сам разбирался?

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск
Категории раздела
Мои статьи [19]
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Друзья сайта
  • Yourdevice