Forum: Compiler & IDEs avr-gcc inline assembler


von inlineasm (Gast)


Lesenswert?

Hi,

ich bastle gerade ein Subtraktionsmakro bei dem ich unschlüssig bin, ob 
der Output-OP res das =& braucht oder nur =. Der erzeugte Code ist mit 
oder ohne & identisch. Ich denke es braucht kein &, da der eraly clobber 
ja schon geschrieben wird, bevor die letzte Verwendung als input 
erfolgt. Was denkt ihr ?

#define sub_u16u16_u16sat(op1_16, op2_16)       \
({                                              \
    uint16_t res = op1_16;                      \
                                                \
    _asm_ __volatile__(                       \
        "sub %A0,%A2"                   CR_TAB  \
        "sbc %B0,%B2"                   CR_TAB  \
        "brcc _1_%="                    CR_TAB  \
        "clr %A0"                       CR_TAB  \
        "clr %B0"                       CR_TAB  \
        "_1_%=:"                        CR_TAB  \
        : /* outputs */                         \
            "=&r" (res)                         \
        : /* inputs */                          \
            "0" (res),                          \
            "r" ((uint16_t)(op2_16))            \
    );                                          \
    res;                                        \
})

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Das "=&" und das "0" widersprechen sich.
Das volatile ist unnötig.

So:
1
#include <stdint.h>
2
3
#define CR_TAB "\n\t"
4
5
static inline uint16_t
6
sub_u16u16_u16sat (uint16_t a, uint16_t b)
7
{
8
    __asm__ ("sub  %A0, %A1"    CR_TAB
9
             "sbc  %B0, %B1"    CR_TAB
10
             "brcc 0f"          CR_TAB
11
             "clr  %A0"         CR_TAB
12
             "clr  %B0"         CR_TAB
13
             "0:"
14
             : "+r" (a) : "r" (b));
15
16
    return a;
17
}

von inlineasm (Gast)


Lesenswert?

ich hätt's ja gern als Makro. Dann wohl so:

#define sub_u16u16_u16sat(op1_16, op2_16)       \
({                                              \
    uint16_t res = op1_16;                      \
                                                \
    _asm_ __volatile__(                       \
        "sub %A0,%A1"                   CR_TAB  \
        "sbc %B0,%B1"                   CR_TAB  \
        "brcc _1_%="                    CR_TAB  \
        "clr %A0"                       CR_TAB  \
        "clr %B0"                       CR_TAB  \
        "_1_%=:"                        CR_TAB  \
        : /* outputs */                         \
            "+r" (res)                          \
        : /* inputs */                          \
            "r" ((uint16_t)(op2_16))            \
    );                                          \
    res;                                        \
})

Allerdings ist das wohl identisch zu:

#define sub_u16u16_u16sat(op1_16, op2_16)       \
({                                              \
    uint16_t res = op1_16;                      \
                                                \
    _asm_ __volatile__(                       \
        "sub %A0,%A2"                   CR_TAB  \
        "sbc %B0,%B2"                   CR_TAB  \
        "brcc _1_%="                    CR_TAB  \
        "clr %A0"                       CR_TAB  \
        "clr %B0"                       CR_TAB  \
        "_1_%=:"                        CR_TAB  \
        : /* outputs */                         \
            "=r" (res)                          \
        : /* inputs */                          \
            "0" (res),                          \
            "r" ((uint16_t)(op2_16))            \
    );                                          \
    res;                                        \
})

, da das + ja auch nur sagt input/output. Sollte damit doch identisch 
sein, oder ?

Gruss und Danke

von (prx) A. K. (prx)


Lesenswert?

inlineasm schrieb:

> ich hätt's ja gern als Makro

Und weshalb?

Ausserdem ist auch hier das "volatile" nicht sinnvoll. Es sei denn du 
willst mit Gewalt auch dann an exakt dieser Stelle subtrahieren, wenn 
der Compiler merkt, dass das Ergebnis nicht benötigt wird oder an 
anderer Stelle billiger ist.

von inlineasm (Gast)


Lesenswert?

ist schon ein grosses altes Projekt, wo alles als Makro's erledigt ist 
und ich ein wenig aufräumen soll. Noch eine Frage: Ist nicht bei 
folgendem Makro ein memory clobber sinnvoll und nötig ?

#define ATOMIC_RESTORE_MEM_SET16(d, s)          \
({                                              \
    _asm_ __volatile__(                       \
        "in _tmp_reg_,__SREG__"       CR_TAB  \
        "cli"                           CR_TAB  \
        "sts %A0,%A1"                   CR_TAB  \
        "out _SREG_,__tmp_reg__"      CR_TAB  \
        "sts %B0,%B1"                   CR_TAB  \
        : /* outputs */                         \
        : /* inputs */                          \
            "m" ((uint16_t)(d)),                \
            "r" ((uint16_t)(s))                 \
    );                                          \
})

Gruss und Danke

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wieder ist das volatile überflüssig. Der memeory-Operand ist Output und 
nicht Input. Der Code funktioniert nicht für Xmega.

von inlineasm (Gast)


Lesenswert?

Nur so aus Neugier, warum würde der Code nicht für XMega funktionieren ?

Danke

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Weil bei Xmega Setzen des I-Flags keine Latenz von 1 Tick hat.

von inlineasm (Gast)


Lesenswert?

Hallo nochmal,

ich habe jetzt mal alle Makro's doch zu Funktionen gemacht. Klappt auch 
alles soweit wie gewollt. Ich habe jetzt nur noch eine Frage/ein Problem 
bei folgender Funktion zur Division:

1
static inline uint16_t div_u32u16_u16(uint32_t op1_32, uint16_t op2_16)
2
{
3
    uint16_t res;
4
5
    __asm__(
6
        "ldi %A0, 17"                   CR_TAB
7
      "mov __zero_reg__, %A0"         CR_TAB
8
9
        "mov %A0,%C1"                   CR_TAB
10
      "mov %B0,%D1"                  CR_TAB
11
        "sub %C1,%C1"                   CR_TAB
12
        "sub %D1,%D1"                   CR_TAB
13
        "rjmp _clc_%="                  CR_TAB
14
15
"_loop_%=:"
16
        "rol %A0"                       CR_TAB
17
      "rol %B0"                       CR_TAB
18
      "rol %C1"                       CR_TAB
19
20
"_clc_%=:"
21
        "cp  %A0,%A2"                    CR_TAB
22
      "cpc %B0,%B2"                   CR_TAB
23
        "cpc %C1,%D1"                   CR_TAB
24
      "brcs _ep_%="                   CR_TAB
25
26
        "sub %A0,%A2"                   CR_TAB
27
        "sbc %B0,%B2"                   CR_TAB
28
        "sbc %C1,%D1"                   CR_TAB
29
30
"_ep_%=:"
31
        "rol %A1"                       CR_TAB
32
        "rol %B1"                       CR_TAB
33
        "dec __zero_reg__"              CR_TAB
34
        "brne _loop_%="                 CR_TAB
35
36
      "com %A1"                       CR_TAB
37
      "com %B1"                       CR_TAB
38
      "mov %A0,%A1"                   CR_TAB
39
      "mov %B0,%B1"                   CR_TAB
40
41
        : /* outputs */
42
            "=&d" (res),
43
            "+r" ((uint32_t)(op1_32))
44
        : /* inputs */
45
            "r" ((uint16_t)(op2_16))
46
          /* clobbers */
47
    );
48
49
    return res;
50
}


Anfänglich wurde mir natürlich immer op1_32 zerschossen. Das konnte ich 
dann mit "+r" verhindern. Soweit geht das jetzt auch. Ich bin allerdings 
noch unschlüssig, ob das der korrekte Weg ist ...

Gruss und Danke

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Klaro, op1_32 wird ja verändert.

Wenn der Compiler das nicht mitbekommt — wie auch sonst? — kann er den 
vermeintlich alten Wert weiter verwenden.

Was soll die Funktion eigentlich tun?

Wenn ein 32-Bit Wert durch 16 Bits geteilt wird, ist doch nicht a priori 
klar, daß das Ergebnis in 16 Bits passt?

von inlineasm (Gast)


Lesenswert?

Selbstredend, aber bei genauer Kenntnis der Einangswertebereiche 
(Funktion wird entsprechend natürlich nur für solche Zahlenbereiche 
verwendet) ist diese Fkt. halt doppelt so schnell, wie die volle 32Bit 
Division mit 33Shift's. Es gibt fast für alle Wertebereiche und 
Operandentypen gesonderte Funktionen, da es in dem Projekt extrem auf 
Rechenzeit ankommt ...

Gruss und Danke

von inlineasm (Gast)


Lesenswert?

Hallo,

nochmal eine Frage. Ich finde irgendwie keine Lösung. Wie bekomme ich 
denn das Zweierkomplement einer RAM-Adresse in so ein Assembler-Makro. 
Ich brauche diesen Wert (lo8 und hi8) für die Offsetbrechnung mittels 
Z-Pointer und subi, sbci in einem Array ???

Gruss und Danke schon mal für die evtl. Hilfe

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Schon mal angeschaut wie's der Compiler macht? ;-)

von inlineasm (Gast)


Lesenswert?

ja klar, aber ich suche ja passende/ensprechende Constraint-Notation für 
ein inline Assemblerstückchen. Der Compiler kann ja das Label direkt in 
den Code einsetzen, was er natürlich auch tut ...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kannst du ja auch machen :-)

Zeig mal den Code den du schon hast.

von inlineasm (Gast)


Lesenswert?

ja, hat jetzt auch funktioniert. War "i"

Danke

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.