avr-gcc inline assembler

Gast #2415128
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;                                        \
})
Persönliche Seite #2415249
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
}
Gast #2415292
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
Gast #2415335
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
Gast #2430227
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
Gast #2430286
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
Gast #2432246
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
Gast #2432363
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 ...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren