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; \ })
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 | } |
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
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.
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
Wieder ist das volatile überflüssig. Der memeory-Operand ist Output und nicht Input. Der Code funktioniert nicht für Xmega.
Nur so aus Neugier, warum würde der Code nicht für XMega funktionieren ? Danke
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
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?
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
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
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 ...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.