-         

Ergebnis 1 bis 8 von 8

Thema: WinAvr: 16bit * 16bit ? Wie gehts ?

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    30.07.2005
    Beiträge
    87

    WinAvr: 16bit * 16bit ? Wie gehts ?

    Anzeige

    Hi Forum,
    ich verwende WinAvr ( WinAVR-20050214 ) und habe ein Problem mit der
    Mulitplikation zweier 16Bit Variablen. Hier mein Code:

    typedef unsigned int us16;
    typedef unsigned long us32;

    us16 a = 8192;
    us16 b = 30000;
    us32 c = 0;

    c = a * b;

    printf("a=%u\r\n", a);
    printf("b=%u\r\n", b);
    printf("c=%lu\r\n", c);

    c = 245760000UL;

    printf("c=%lu\r\n", c);

    Die Ausgabe ist:
    a=8192
    b=30000
    c=0
    c=245760000

    Warum ist c = 0 ? Eigentlich erwarte ich 245760000. Da c 32Bit gross ist
    sollte auch kein Überlauf auftreten. Wenn ich c = 245760000UL setzte
    dann wird der Wert von printf richtig ausgegeben. An der Ausgabe kann es nicht liegen.
    Also warum ist c = 0 und wie bekomm ich den AVR dazu den Wert korrekt zu berechnen ?

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Alter
    48
    Beiträge
    2.731
    Hallo,
    Du musst vor dem rechnen a und b in long umwandeln, damit long rauskommt, kannst mal probieren:

    c = (long)a * (long)b;

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    30.07.2005
    Beiträge
    87
    hi linux,
    ok mit dem long Cast klappt es, dank dir. Allerdings ist mir nicht klar warum ich eine 16Bit Variable erst in 32Bit konvertieren muss ? Nach einem Cast auf long wird für die Multiplikation __mulsi3 aufgerufen, d.h. es wird wirklich 32Bit*32Bit gerechnet obwohl 16Bit*16Bit ausreichen würde. Da geht mir mein kompletter Geschwindigkeitsvorteil flöten. In den App Notes von Atmel sind Assembler Beispiele in den 16Bit*16Bit=32Bit gerechnet wird, die sind erheblich schneller. Kann ich den compiler austricksen oder muss ich die Multiplikation selber implementieren ?

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    evtl gibts ne __umulhisi3 oder __mulhisi3.
    Am besten schaust das in der Maschinenbeschreibung nach oder in der Quelle der libgcc2 (libgcc2.S)
    Disclaimer: none. Sue me.

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    30.07.2005
    Beiträge
    87
    Danke für den Tip. Ich habe mir mittlerweile eine Assembler Funktion geschrieben. für eine 16Bit*16Bit=32Bit Multiplikation braucht sie nur 24 Takte

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    30.09.2004
    Ort
    In der Nähe von Esslingen am Neckar
    Beiträge
    706
    Hi,
    kannst du mal die ASM Funktion posten?
    Gruß Michi

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Entsprechende asm-Quellen findest du bei den Compilerquellen, und zwar in der libgcc2.S
    Disclaimer: none. Sue me.

  8. #8
    Benutzer Stammmitglied
    Registriert seit
    30.07.2005
    Beiträge
    87
    Hier meine Funktion:

    #include "avr/io.h"

    ;------------------------------------------------------------------------------
    ; Funktion : Unsigned Integer Multiplikation
    ; Taktzyklen: 24
    ; Register : r0 r1 r18 r19 r20 r21 r22 r23 r24 r25 r30
    ;
    ; 32Bit = 16Bi * 16Bit
    ; CH:CMH:CML:CL = AH:AL * BH:BL
    ;------------------------------------------------------------------------------
    ; Unsigned 16Bit Faktor A
    #define AL r24
    #define AH r25

    ; Unsigned 16Bit Faktor B
    #define BL r22
    #define BH r23

    ; Unsigned 32Bit Produkt C
    #define CL r22
    #define CML r23
    #define CMH r24
    #define CH r25

    ; 0 Register
    #define ZERO r30

    ; Unsigned 16Bit Produkt aus AL * BL
    #define ALBLL r18
    #define ALBLH r19

    ; Unsigned 16bit Produkt aus AH * BH
    #define AHBHL r20
    #define AHBHH r21

    ; Unsigned Integer Multiplikation
    .global us32Mul16_16_32
    .func us32Mul16_16_32
    us32Mul16_16_32:
    clr ZERO ; r30 = 0 1
    mul AH, BH ; AH * BH 2
    movw AHBHL, r0 ; (AH * BH) -> (AHBHL:AHBHH) 1
    mul AL , BL ; AL * BL 2
    movw ALBLL, r0 ; (AL * BL) -> (AHBHL:AHBHH) 1
    mul AH, BL ; AH * BL 2
    add ALBLH, r0 ; ALBLH + (AH * BL)l 1
    adc AHBHL, r1 ; AHBHL + (AH * BL)h 1
    adc AHBHH, ZERO; AHBHH + Carry 1
    mul BH, AL ; BH * AL 2
    add ALBLH, r0 ; ALBLH + (BH * AL)l 1
    adc AHBHL, r1 ; AHBHL + (BH * AL)h 1
    adc AHBHH, ZERO; AHBHH + Carry 1
    movw CL , ALBLL ; ALBLL -> CL 1
    movw CMH, AHBHL; AHBHL -> CMH 1
    clr r1 ; r1 = 0 1
    ret ; return 4
    .endfunc
    ;------------------------------------------------------------------------------

    __umulhisi3 und __mulhisi3 aus der libgcc fand ich von der Laufzeit
    nicht so berauschend.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •