Gast
#5557975
Hallöschen, wie bekomme ich den
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
Wie bekomme ich es hin das ich in "0x17" den Wert von "x" rein schreibe?
|
Anzeige
|
Inline Assembler in C
Gast
#5557975
Hallöschen, wie bekomme ich den
Wie bekomme ich es hin das ich in "0x17" den Wert von "x" rein schreibe?
Gast
#5557993
uint8_t *ptr = 0x17; ... ptr, r123..
Gast
#5557996
pointer schrieb: > uint8_t *ptr = 0x17; > > ... ptr, r123.. Sollte möglichst alles in Inline geschehen.. Ich denke der Compiler optimiert das am besten:
wenn du die Funktion inline verwenden willst, dann definiere sie inline.
Gast
#5558004
Benjamin S. schrieb: > Ich denke der Compiler optimiert das am besten:uint8_t *ptr = > 0x17; > wenn du die Funktion inline verwenden willst, dann definiere sie inline. > inline void setDdrLed( uint8_t x ) > { > asm ( > "ldi r16, %0\n\t" > "out 0x17 , r16" > : "+r" ( x ) > ); > } Okay, habe ich übersehen. Geht aber nach wie vor nicht. Du kannst x mit 17 belegen beim Aufruf
oder willst du beim "out 0x17 , r16" das 17 dynmisch haben?
weitere Info gibts u.a. hier: https://rn-wissen.de/wiki/index.php?title=Inline-Assembler_in_avr-gcc
Gast
#5558011
Benjamin S. schrieb: > Du kannst x mit 17 belegen beim AufrufsetDdrLed(0x17) > oder willst du beim "out 0x17 , r16" das 17 dynmisch haben? > inline void setDdrLed( uint8_t x, uint8_t reg ) > { > asm ( > "ldi r16, %0\n\t" > "out %1 , r16" > : "+r" ( x ) > : "+r" ( reg ) > ); > } > > weitere Info gibts u.a. hier: > https://rn-wissen.de/wiki/index.php?title=Inline-A... Ich würde gerne in das Register bzw. an die Adresse 0x17 den Wert den ich übergebe, rein schreiben. Thorsten K. schrieb: > Ich würde gerne in das Register bzw. an die Adresse 0x17 den Wert den > ich übergebe, rein schreiben. Das kannst du auch ohne Assembler machen:
Oder besser lesbar, wie bereits geschrieben wurde:
Wenn es dir darum geht, den Inline-Assembler von gcc besser zu verstehen, dann sage das bitte deutlich an.
Gast
#5558168
S. R. schrieb: > Thorsten K. schrieb schrieben wurde:static func(uint8_t x) > { > uint8_t *ptr = (uint8_t*)0x17; > *ptr = x; > } > > Wenn es dir darum geht, den Inline-Assembler von gcc besser zu > verstehen, dann sage das bitte deutlich an. Ja ich würde es gerne in Inline Assembler machen, damit ich es auch besser verstehe.. Benjamin S. schrieb: > Du kannst x mit 17 belegen beim Aufruf >
> > oder willst du beim "out 0x17 , r16" das 17 dynmisch haben? > >
Welcher μC soll das denn sein? Aus dem ersten Post zu schließen ein AVR8. Wo hat der ein OUT mit Port-Adresse in einem Register? Das geht nur über die MEM-Adresse (idR IO-Adresse+0x20 also 0x37) in einem Pointer-Register. Wozu Inline-Assembler, wenn man auch "DDRB = x" schreiben kann? Mario M. schrieb: > Wozu Inline-Assembler, wenn man auch "DDRB = x" schreiben kann? Weil "DDRB" hier "uint8_t reg" heißt?!
Gast
#5558204
Ich würde es halt mal gerne wissen wie man das damit macht. Es ist ein Tiny2313. Eigentlich ist der Port mir egal.. Also welcher..
Gast
#5558232
> Ich würde es halt mal gerne wissen wie man das damit macht. Wie wär's mit Google? Ne Suche nach "avr-gcc inline assembler" gibt als ersten deutschen[1] Treffer: https://rn-wissen.de/wiki/index.php?title=Inline-Assembler_in_avr-gcc [1] Wobei ich mir nicht sicher bin, ob Deutsch die passende Sprache ist ;-)
Gast
#5558236
foobar schrieb: >> Ich würde es halt mal gerne wissen wie man das damit macht. > > Wie wär's mit Google? Ne Suche nach "avr-gcc inline assembler" gibt als > ersten deutschen[1] Treffer: > > https://rn-wissen.de/wiki/index.php?title=Inline-A... > > [1] Wobei ich mir nicht sicher bin, ob Deutsch die passende Sprache ist > ;-) Ja habe ich schon gegoogelt.. Diese Seite habe ich auch schon aufgerufen.. Bin nicht schlauer geworden.. Thorsten K. schrieb: > Bin nicht schlauer geworden.. Das tut mir aber Leid. Woran mangelt's denn?
Gast
#5558385
> Diese Seite habe ich auch schon aufgerufen.. Bin nicht schlauer > geworden.. Die Seite erklärt aber gut und ausführlich. Besser wirst du's hier auch nicht bekommen. Evtl solltest du dir nen anderes Thema suchen ...
Gast
#5558538
foobar schrieb: >> Diese Seite habe ich auch schon aufgerufen.. Bin nicht schlauer >> geworden.. > > Die Seite erklärt aber gut und ausführlich. Besser wirst du's hier auch > nicht bekommen. Evtl solltest du dir nen anderes Thema suchen ... Man könnte es jedoch wenigstens mal versuchen. Ich kann auf den Port zugreifen. Das heißt wenn ich jetzt ne LED dran hänge fängt diese auch zu leuchten, je nach dem welches Bit ich setze. Bei den Ausgängen jedoch funktioniert das eben nicht. Muss doch einen einfachen Grund haben.. Thorsten K. schrieb: > Geht aber nach wie vor nicht. Was heißt "geht nicht"? Nimmt er Compiler es nicht an? Kommt der Wert nicht im Register an? Sollte es so sein: Woran hast du das erkannt?
Gast
#5558606
Rolf M. schrieb: > Thorsten K. schrieb: >> Geht aber nach wie vor nicht. > > Was heißt "geht nicht"? Nimmt er Compiler es nicht an? Kommt der Wert > nicht im Register an? Sollte es so sein: Woran hast du das erkannt? Der Compiler zeigt mir keine warnings oder Fehlermeldungen an. Ich vermute mal das der Wert nicht ins Register rein geschrieben wird. Thorsten K. schrieb: > foobar schrieb: >> Die Seite erklärt aber gut und ausführlich. Besser wirst du's hier auch >> nicht bekommen. Evtl solltest du dir nen anderes Thema suchen ... > > Man könnte es jedoch wenigstens mal versuchen. > Ich kann auf den Port zugreifen. Das heißt wenn ich jetzt ne LED dran > hänge fängt diese auch zu leuchten, je nach dem welches Bit ich setze. > > Bei den Ausgängen jedoch funktioniert das eben nicht. Du sprichst in Rätseln. Was meinst du denn bitte mit "den Ausgängen"? Inwiefern unterscheiden sich irgendwelche Ausgänge von Portpins, an denen LED hängen? Und was genau soll "funktioniert nicht" heißen? Klingt gerade überhaupt nicht nach einem Softwareproblem, am wenigsten nach einem Problem mit Inline-Assembler. Thorsten K. schrieb: >
Nun, x ist ja bereits im Register r24 (das macht der Aufrufer). Das ldi ist somit falsch und gibt eine Fehlermeldung:
Außerdem wird alles wegoptimiert, da nicht volatile. So geht es:
Steht aber alles schön erklärt im: https://rn-wissen.de/wiki/index.php?title=Inline-Assembler_in_avr-gcc Peter D. schrieb: > Nun, x ist ja bereits im Register r24 (das macht der Aufrufer). In welchem Register das an die Funktion übergeben wird, muss deinem asm-Block egal sein. Wesentlich ist nur, dass das "+r" sagt, dass dein Code den Wert in einem (beliebigen) Register erwartet. ldi will aber einen Immediate-Wert und kein Register als zweiten Operanden. Peter D. schrieb: > void setDdrLed( uint8_t x ) > { > asm volatile ( > "mov r16, %0\n\t" > "out %1 , r16\n\t" > : "+r" ( x ) > : "M" (_SFR_IO_ADDR (DDRB)) > ); > } Warum ist x hier als Output-Operand aufgeführt? Es wird doch ausschließlich gelesen. Man könnte sich den Umweg über r16 übrigens noch sparen. Und man kann den Operanden zur Übersicht auch Namen geben. Dann würde das ganze so aussehen:
Carl D. schrieb: > Mario M. schrieb: >> Wozu Inline-Assembler, wenn man auch "DDRB = x" schreiben kann? > > Weil "DDRB" hier "uint8_t reg" heißt?! Genau darum kann es auch gar nicht gehen, C hin, Inline-Assembler her. Der Operand für OUT muss eine Compilezeit-Konstante sein, denn die Adresse des Ports wird in den Befehl hinein codiert. Deshalb ist ja auch OUT auf einen vergleichsweise kleinen Portadressraum eingeschränkt. Wenn es unbedingt zur Laufzeit einstellbar sein soll, kann man nur üben den (langsameren) Alias der Portadresse im Speicheradressraum gehen. Das ist in der avr-libc-FAQ beschrieben.
Gast
#5558870
Rolf M. schrieb: > asm volatile ( > "out %[Register], %[Value]\n\t" > : /* Leere Liste */ > : [Value]"r" ( x ), [Register]"M" (_SFR_IO_ADDR (DDRB)) > ); Das sieht viel versprechend aus ;) werde ich später mal testen. Thorsten K. schrieb: > Das sieht viel versprechend aus Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als Makro übergeben werden. Den kann man nicht durch einen Variablennamen ersetzen. Ansonsten ist das aber wirklich nichts anderes, als gleich in C zu schreiben:
Jörg W. schrieb: > Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als > Makro übergeben werden. Den kann man nicht durch einen Variablennamen > ersetzen. Wo hat er das denn gewollt? Thorsten K. schrieb: > Ich würde gerne in das Register bzw. an die Adresse 0x17 den Wert den > ich übergebe, rein schreiben. Ich interpretiere das so, dass der Wert als dynamischer Parameter übergeben werden soll, aber nicht die Adresse des Registers. > Ansonsten ist das aber wirklich nichts anderes, als gleich in C zu > schreiben: > PORTB = x; Es geht ihm ja nur darum, inline assembler zu verstehen. Da ist es nicht von Nachteil, mit was einfachem anzufangen. Rolf M. schrieb: > Es geht ihm ja nur darum, inline assembler zu verstehen. Da ist es nicht > von Nachteil, mit was einfachem anzufangen. Dafür gibt's das Inline Assembler Cookbook. https://www.nongnu.org/avr-libc/user-manual/inline_asm.html
Gast
#5559066
Jörg W. schrieb: > Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als > Makro übergeben werden. Den kann man nicht durch einen Variablennamen > ersetzen. > > Ansonsten ist das aber wirklich nichts anderes, als gleich in C zu > schreiben: > PORTB = x; Das ist mir soweit auch klar -.-* Ich möchte doch einfach nur mein Wissen in Inline ASM ein wenig verstärken.. Und durch das belesen, bin ich halt auch nicht weiter gekommen..
Gast
#5559068
Jörg W. schrieb: > Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als > Makro übergeben werden. Den kann man nicht durch einen Variablennamen > ersetzen. Wie meinst du das? Die Adresse von PORTx? Welches Makro? Thorsten K. schrieb: > Und durch das belesen, bin ich halt auch nicht weiter gekommen. Dann schreib lieber mal, wo du nicht weiterkommst. Das relativ simple Beispiel mit den IO-Port-Ausgaben steht im genannten Inline Asm Cookbook ja bereits ziemlich weit oben. Nach unten wird's dann immer tiefgehender. Diese Constraints mögen auf den ersten Blick ziemlich verwirrend aussehen. Letztlich bilden sie das ab, was der Compiler intern in seinen Zwischensprachen ebenfalls benutzt, um die einzelnen Operanden zu markieren. Dadurch kann man die Aufteilung, welche Daten beispielsweise in Registern gehalten werden und welche im Speicher bleiben (und dann temporär in Register kopiert werden müssen), bis zu einem Zeitpunkt nach hinten schieben, bei dem der Optimierer dann entscheiden kann, was wie zugegriffen wird, sodass der gesamte Code möglichst effizient wird. „Harte“ Registerzuteilungen sollte man folglich auch im Inline-Assembler vermeiden und stattdessen Variablen mit passendem Constraining benutzen. Schau dir dein einleitendes Beispiel an: du hast Register r16 hart vorgegeben (und müsstest es in die "clobber"-Liste eintragen). Wenn du stattdessen deinen OUT-Befehl mit einem Operanden versiehst, der passendes Constraining bekommt (OUT braucht ein beliebiges Register, also "r"), dann kann der Compiler sich darum kümmern, dass der auszugebende Wert gleich mal in einem solchen Register berechnet wird, sodass man nicht nochmal umkopieren muss.
1) Natürlich wird aus dem Controller etwas ausgegeben, aber das Inline-Asm-Statement gibt in diesem Kontext nichts in seine C-Umgebung zurück. Daher gibt es hier nur input operands. Obige Funktion compiliert zu:
r24 ist hierbei das Register, in dem die Funktion den ersten Parameter übergeben bekommt. Der Compiler muss nichts extra umkopieren, er kann dieses Register gleich für den OUT-Befehl benutzen. Bei deiner Variante hätte er es erst (sinnlos) nach r16 umkopieren müssen. Thorsten K. schrieb: > Die Adresse von PORTx? Welches Makro? PORTx ist ein Makro.
Gast
#5559092
Jörg W. schrieb: > : [port] "I" (_SFR_IO_ADDR(PORTB)), Okay. Und kann ich meiner Funktion auch "PORTB" mitgeben? Also quasie..
Thorsten K. schrieb: > Und kann ich meiner Funktion auch "PORTB" mitgeben? Nein. Schrieb ich doch weiter oben, sowas gibt die AVR-Architektur schlicht nicht her.
Gast
#5559138
Jörg W. schrieb: > Thorsten K. schrieb: > Das sieht viel versprechend aus > > Ist allerdings nicht das, was du oben gewollt hast: PORTB muss hier als > Makro übergeben werden. Den kann man nicht durch einen Variablennamen > ersetzen. > > Ansonsten ist das aber wirklich nichts anderes, als gleich in C zu > schreiben:PORTB = x; Also Makro übergeben. Kannst du mir bitte ein konkretes Beispiel posten..? Wenn PORTB oder DDRB ein Makro ist, müsste ich das doch übergeben können? Thorsten K. schrieb: > Wenn PORTB oder DDRB ein Makro ist, müsste ich das doch übergeben > können? Nein. Mach dich mal mit dem Konzept von Makros vertraut: das ist doch nur eine Textersetzung. Er würde ja bei der Übergabe aufgelöst werden müssen. Unabhängig von Makro oder nicht, scheinst du immer noch nicht verstanden zu haben, dass beide Operanden eines OUT-Befehls zu dem Zeitpunkt, da es der Assembler vorgesetzt bekommt, feststehende Konstanten sein müssen. Das beißt sich mit deinem Wunsch, sie als Parameter einer Funktion zu übergeben, denn dann würde man ja den konkreten Port erst zur Laufzeit festlegen. Wenn du sowas willst, musst du über die Port-Aliase im Speicheradressbereich gehen. Wie das geht, ist hier beschrieben: https://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass
Gast
#5559232
Jörg W. schrieb: > Unabhängig von Makro oder nicht, scheinst du immer noch nicht verstanden > zu haben, dass beide Operanden eines OUT-Befehls zu dem Zeitpunkt, da es > der Assembler vorgesetzt bekommt, feststehende Konstanten sein müssen. > Das beißt sich mit deinem Wunsch, sie als Parameter einer Funktion zu > übergeben, denn dann würde man ja den konkreten Port erst zur Laufzeit > festlegen. Wenn du sowas willst, musst du über die Port-Aliase im > Speicheradressbereich gehen. Wie das geht, ist hier beschrieben: > > https://www.nongnu.org/avr-libc/user-manual/FAQ.ht... Das geht dann aber nur in C Code? Thorsten K. schrieb: > Das geht dann aber nur in C Code? Was geht nur in C-Code? Zugriff auf IO-Ports über Speicherbereiche? Natürlich geht das auch direkt in Assemblercode, der C-Compiler erzeugt ja letztlich nur Assemblercode. Die Speicheradresse eines IO-Ports bekommt man mit _SFR_MEM_ADDR() – steht natürlich alles in der Doku. ;-) Mir stellt sich trotzdem noch die Frage, warum du für simple Dinge, die in C völlig unproblematisch und einfach gehen, erst die Verrenkungen über inline asm machen willst. Wirklich lernen kann man an der Stelle nicht so viel … Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|