Hallo kann mir jemand genua den Unterschied zwischen den Befehlen STD und STS erklären bei Atmel asm. ich frage da ich test1 als static angelegt habe und test2 als volatile. Gibt es da vorteile bzw nachteile? test1=x; 818D LDD R24,Y+5 Load indirect with displacement 819E LDD R25,Y+6 Load indirect with displacement 93900101 STS 0x0101,R25 Store direct to data space 93800100 STS 0x0100,R24 Store direct to data space test2=x; 818D LDD R24,Y+5 Load indirect with displacement 819E LDD R25,Y+6 Load indirect with displacement 839C STD Y+4,R25 Store indirect with displacement 838B STD Y+3,R24 Store indirect with displacement
STS geht mit X,Y und Z, benötigt aber eine diskrete Adresse. STD geht nur mit Y und Z, erlaubt es jedoch bei einem variablen Offset eine "feste Adresse" anzuspringen, also [var. Offset]+[Konstante]. Vielleicht hats noch andre Vor-/Nachteile.
Hallo, manchmal braucht man eine konkrete Situation um zu merken, die oder die Adressierung ist hier gut. Nehmen wir mal an, Du hast ein Programm, das Datensätze mit z.B. 4 Byte erzeugt. Dann kannst Du beim abspeichern in Y die Dresse eines Datensatzes laden und über das Displacement die entsprechenden Daten abspeichern. Das ganze kannst Du in eine Routine packen. Die Routine erwartet in Y die Basisadresse und speichert dann die 4 Bytes mit dem Displacement 0,1,2 und 3 ab. Du kannst die Routine also für beliebige Speicheroperationen nehmen. Bei STS geht das nicht, da dort eine direkte Adresse angegeben wird. Die Routine zum Abspeichern würde immer die gleiche Adresse nehmen. Würde so keinen Sinn machen - wenn man mehrere Datensätze abspeichern will. Gruß Wolfgang www.ibweinmann.de brushless control
Der Unterschied ist nicht static<->volatile, sondern static<->nicht-static. Mit static definierst Du, dass eine lokale Variable beim nächsten Aufruf der betreffenden Funktion noch denselben Wert hat, den sie beim letzen Mal hatte. Solche Variablen legt der Compiler genauso an wie globale Variablen, nur dass sie halt nicht global verfügbar sind. Das heißt, dass static Variablen zumindest im AVR-Kontext immer eine feste Adresse haben, auf die mit LDS/STS zugegriffen wird. Dem gegenüber bedeutet volatile, dass eine Variable, wie die Bezeichnung schon andeutet, flüchtig oder genauer: nicht vorhersagbar veränderlich ist, man sich also auf ihren Wert nicht verlassen kann, sofern man ihn nicht gezielt setzt. Solche lokalen Variablen legt der Compiler nur nach Bedarf, das heißt beim Aufruf einer Funktion, auf dem Software-Stack an (der bei praktisch allen AVR-C-Compilern per Y und LDD/STD verwaltet wird), und räumt sie beim Verlassen der Funktion wieder ab - wie er es normal aber auch mit jeder nicht-static lokalen Variablen macht, weswegen volatile bei lokalen Variablen nur innerhalb der jeweiligen Funktion einen Unterschied machen kann, wenn überhaupt. Ich habe selber in AVR-C-Programmen bisher nie volatile lokale Variablen verwendet, und nie irgendwelche Nachteile davon erfahren. Nur in den io register headers, die letztlich globale Adressen definieren, ist volatile unbedingt erforderlich. Beste Grüße Johannes
@Johannes Das heist also Variablen die in global definiert werden. Und diese in der main Funktion sowie in einer ISR genutzt werden müssen garnicht volatile sondern als static deklariert werden.
Für das Hauptprogramm sind Veränderungen, die von einer ISR vorgenommen werden, genauso unvorhersagbar, wie die Aktivitäten von Ports. Also ist auch hier "volatile" Pflicht. Egal ob global, static oder automatic. Lokale Variablen von Funktionen des Hauptprogramms werden allerdings üblicherweise nicht von einer ISR angesprochen. Exotische und hoch gefährliche Ausnahme: Wenn man die Adresse einer lokalen Variablen global bekanntgibt, kann eine ISR darauf zugreifen.
Hallo, @Wolfgang: naja, das kann ich normalerweise genausogut mit ST Y+,Wert erledigen, wenn ich jetzt nichts übersehe. Was ich öfter vermisse, ist ein Register-Displacement mit z.B. Z, also STD (Z+R16),Wert. Wie hieß es woanders so schön? Indirekt indiziert mit Register-Offset ;) Sowas kostet beim AVR immer 16Bit Addition/Subtraktion mit Retten des Index-Registers. Gruß aus Berlin Michael
Was meinst Du mit "Variablen die in global definiert werden"? Ansonsten meinte ich erstmal nicht die globals sondern die lokalen Variablen, z.B. ganz grob: char time_tick; // global void main(void) { char x1,x2; // local while(1) { if (time_tick) { time_tick = 0; x1 = wasweissich(~PINA); if (x1!=x2) { // x1 verwursten x2 = x1; } } } } char wasweissich(char y) { static unsigned char z; // noch ne local, aber static if (y==0) z = 0; else z |= y; return z; } // timer ISR void TIM0_OVF(void) { time_tick = 1; } Keine Ahnung, wie sinnvoll dieser Code wirklich ist, aber hier ist time_tick eine globale Variable, die ohne weiteres Zutun sowohl main als auch der ISR bekannt ist, und im asm von beiden per LDS/STS benutzt wird. Dann kommen x1/x2/y als lokale Variablen, die nach Gebrauch wieder aufgelöst werden (x1 und x2 nur deshalb nicht, weil main endlos loopt) und, sofern sie nicht in die AVR-Register gemappt werden, auf dem Software-Stack landen, und schließlich z, die als static beim erneuten Aufruf von wasweissich noch ihren letzten Wert haben soll und deshalb wie timer_tick per LDS/STS gehandelt wird. Verstehst Du jetzt, was ich mein(t)e? Gruß Johannes
Und genau so ein "tick" muss "volatile" sein. Alle anderen x*,y*,z* sind wurscht.
@A.K. ein klares Jein :-) Bestenfalls stimme ich Dir noch bei den globals zu, andererseits sind die bei näherer Betrachtung eh grundsätzlich volatile, und werden von einem ordentlichen Compiler auch so gehandhabt. Und bei locals, egal ob static und automatic, gibt es per definitionen ebenso grundsätzlich keine weitere Instanz, die die sehen darf - und wenn doch, hat nur Dein Compilerbauer absoluten Mist gebaut. @Michael, in asm kannst Du grundsätzlich zwar machen, was Du lustig bist, nur sobald Du einen Software-Stack-Frame anlegst, mit dem auch ISRs klarkommen sollen, darfst Du Deinen Frame-Pointer (typ. Y) innerhalb einer Funktion nicht mehr verändern, zumindest nicht, solange Du nicht absolut sicher bist, die damit freigegebenen Werte bestimmt nicht mehr zu brauchen. Mag sein, dass ich da über die Jahre etwas bequem geworden bin, wenn ich in meinen 500-Zeilen-asm-Funktionen lieber ein sbiw r28,x am Anfang und ein adiw r28,x am Ende und zwischendurch ldds und stds verwende, als die ganze Zeit mitzuzählen, wie viele Y+ und -Y nun gerade gelaufen sind. Gruß auch an Wolfgang Johannes
"andererseits sind die bei näherer Betrachtung eh grundsätzlich volatile" Nein. "und werden von einem ordentlichen Compiler auch so gehandhabt" Nein. Schon ein einfacher Compiler darf davon grundsätzlich ausgehen, dass er in Codeblöcken ohne störenden Funktionsaufruf auch global sichtbare Daten rein lokal verarbeiten darf. Und einen global optimierenden Compiler muss auch ein Funktionsaufruf nicht stören, wenn er die entsprechenden Eigenschaften dieser Funktion kennt. Wenn sich ein Compiler so verhalten sollte, als sei jede globale Variable "volatile", dann ist das kein Beweis für deine These. "Und bei locals, egal ob static und automatic, gibt es per definitionen ebenso grundsätzlich keine weitere Instanz, die die sehen darf" Den Namen nicht, die Daten schon. Beispiel: global scope: volatile struct timer *root; local scope: volatile struct timer t; if (root == NULL) root = &t; und schon ist der Inhalt der lokalen Variablen "t" für eine ISR sichtbar. Der Fall ist übrigens nicht exotisch. Das Beispiel hier ist ein temporär angelegter Timer, der sich in einer globalen Timerliste einklinkt, die von einem Interrupt verarbeitet wird. "und wenn doch, hat nur Dein Compilerbauer absoluten Mist gebaut" Hast du damit Erfahrung?
Einfaches Beispiel in dem global scope kein bischen volatile ist. Mit avr-gcc: extern unsigned char port; void f(void) { port = 1; port = 2; port = 0; } Jeder halbwegs mittdenkende Compiler lässt die beiden ersten Statements weg.
Und falls dir das zu absurd aussieht, ein erweitertes Beispiel: #include <string.h> extern volatile unsigned char state; extern char buffer1[100], buffer2[100]; void f(void) { state = 1; memcpy(buffer1, buffer2, 100); state = 2; memcpy(buffer2, buffer1, 100); state = 0; } Lass das "volatile" weg, und die ISR kriegt nicht mehr mit, dass grad jemand an den Puffern rumspielt, weil "state" erst ganz am Ende angefasst wird.
Hallo A.K. Du hast recht, ich hab etwas zu eng gedacht, nämlich modul-global. Was mir klar wurde, als ich Dein erstes "extern" las... Ok, damit relativiert sich das eine und andere von dem, was ich schrieb, denn modul-global ist ja auch zugleich modul-local. Ach, ich liebe diese scope-Geschichten! :-) Übrigens fand ich Deine Beispiele weder exotisch noch absurd, höchstens etwas gefährlich. Speziell das aus Deinem ersten Posting: Wenn Du nämlich eine lokale Variable per Pointer globalisierst, darfst Du auf keinen Fall vergessen, den Pointer beim Verlassen der betreffenden Funktion wieder auf NULL zu setzen. Sonst... Na ich denke, Deine Phantasie wird ausreichen, Dir auszumalen, welche "Wunder" dann passieren. Ansonsten ging das Beispiel etwas vorbei an dem, wovon ich geredet hatte. Mein Ansatz waren die Vorgaben des Compilers, und nicht, dass man per Code immer irgendwie "drumherumtricksen" kann. Zumindest in allen Sprachen, die Pointer unterstützen. Abschließend noch: Du fragtest, ob ich Erfahrungen mit Mist seitens des Compilerbauers habe. Ja, das ist aber schon ein paar Jährchen her, und den konkreten Kontext habe ich inzwischen vergessen. Ich weiß nur noch, dass es ein C für 8bit Prozze war, und dass es mir gleichnamige lokale Variablen ziemlich frei nach Laune durcheinandergewürfelt hat. Und noch eine Frage, weil ich gcc nicht näher kenne: Wie verfahren da Assembler und Linker, wenn man in asm-Modulen irgendwelche C-Variablen referenziert? Oder konkreter: Unterscheidet gcc auf asm-Ebene noch zwischen "ganz global" und modul-global? Beste Grüße Johannes
Die oben gezeigte Notwendigkeit von volatile hat mit dem Namensraum (scope) nichts zu tun, sie besteht sowohl bei external scope ("ganz global"?) als auch bei file scope ("modul-global"?) als auch bei lokalen Daten. Wenn man in meinem "port=0" Beispiel "extern" weglässt oder durch static" ersetzt, ändert sich am Problem überhaupt nichts. Dass es etwas gefährlich ist, die Adresse einer lokale Variablen global bekanntzugeben, hatte ich oben schon selber erwähnt. Im Assembler definierte Namen, ob Daten oder Funktionen, sind nur dann global bekannt, wenn das auch angegeben wird (.extern). Im Assembler lediglich benutzte Namen, sind automatisch extern. Uralte etwas zweifelhafte Unix-Tradition.
Also erstmal denke ich, dass mein "ganz global" und "external scope" sowie mein "modul-global" und "file scope" dasselbe sind. Wie gesagt, ich liebe diese Scope-Geschichten (grrrr :-), denke allerdings, dass wir beide C von jeweils unterschiedlichen Richtungen her betrachten. Ich, wie meine Postings hier wohl deutlich machen, von "unten", also von der asm-Seite her, wo C als der "bessere Assembler" erscheint, und Du offenbar von oben, was ich aus Deiner "Prinzipienreiterei" (nicht böse gemeint) und Deinem Bezug auf Unix schließe... "Wenn man in meinem "port=0" Beispiel "extern" weglässt oder durch "static" ersetzt, ändert sich am Problem überhaupt nichts." Ich begreife inzwischen zwar die volatile-Geschichte, allerdings nicht mehr, was extern noch damit zu tun haben soll. Ich mein, entweder ist die betreffende Variable file scope oder lokal definiert, und dann ist das extern wumpe, oder sie ist external scope, und dann ist extern Pflicht, völlig unabhängig vom volatile. Oder ist das bei gcc anders? Im übrigen habe ich, wie gesagt, bisher nie volatile lokale Variablen verwendet, und nie irgendwelche Nachteile davon erfahren. "Im Assembler definierte Namen, ob Daten oder Funktionen, sind nur dann global bekannt, wenn das auch angegeben wird (.extern). Im Assembler lediglich benutzte Namen, sind automatisch extern. Uralte etwas zweifelhafte Unix-Tradition." Nach ersterem hatte ich gar nicht gefragt, aber interessant: Auf asm-Ebene gibt es demnach keinen Standard mehr. Letzteres entspricht allerdings auch meiner Erfahrung, sprich: file scope gibt es auf asm-Ebene nicht mehr. Richtig? Unlogisch wäre das jedenfalls nicht, weil die Möglichkeiten von C dort ja nicht mehr greifen können. Ich würde das übrigens nicht Unix anlasten, denn schließlich ist C die Henne und Unix das Ei, auch wenn beide parallel entwickelt wurden. Im übrigen Danke für Deine Antworten. Ich hab damit jetzt etwas klarbekommen, was mir vorher keines der vielen Tutorials, die ich schon studiert habe, wirklich klarmachen konnte. Einen schönen Restsonntag noch Johannes
Ich hatte deinen "eng gedacht" Kommentar offenbar anders interpretiert als er gemeint war (soll heissen: hab jetzt keinen Schimmer mehr wie er gemeint war ;-). Noch so ein sprachliches Kleinod: Wenn garnix dransteht und Funktion/Variable nicht static sind, dann ist das auch external scope. Auch wenn kein "extern" dransteht. "Auf asm-Ebene gibt es demnach keinen Standard mehr." Geradezu per Definition. ;-) "file scope gibt es auf asm-Ebene nicht mehr." Doch. Alles was in ASM definiert wird, hat file scope, sofern nicht mit .extern verziert. Nur was in ASM nicht definiert wird, hat implizit external scope. Gilt aber nur für GNU-as und allerlei Unix Assembler. PC Assembler sind da anders.
Oha, hab ich mich wieder so unverständlich ausgedrückt? Na, ich meinte "zu eng gedacht" in der Richtung, dass ich "nur" modul-global gedacht und die modul-lokalen Aspekte dabei übersehen hatte... "Noch so ein sprachliches Kleinod: Wenn garnix dransteht und Funktion/Variable nicht static sind, dann ist das auch external scope. Auch wenn kein "extern" dransteht." Kann ich nicht ganz nachvollziehen. Also mein iccavr Compiler, der (von unabhängigen Stellen wohl soweit bestätigt) ANSI-konform ist, händelt alle file-globalen Funktionen/Variablen zwar als globals, was das Erscheinen im map file angeht, verlangt aber von allen C-files, die sich darauf beziehen wollen, eine explizite extern Deklaration. Wenn ich dagegen aus einem asm-File darauf zugreifen will, geht das völlig direkt und problemlos. Oder ist das genau das, was Du meintest? ""file scope gibt es auf asm-Ebene nicht mehr." Doch. Alles was in ASM definiert wird, hat file scope, sofern nicht mit .extern verziert. Nur was in ASM nicht definiert wird, hat implizit external scope. Gilt aber nur für GNU-as und allerlei Unix Assembler. PC Assembler sind da anders." Ähm, da reden wir wohl noch ein Stück aneinander vorbei. Oder vielleicht auch nicht. Also ich meinte, dass ich in asm keinen *file scope* wie in C mehr definieren kann, sondern dass jede "verzierte" Definition (beim iccavr assembler per .globl oder mit "::" nach dem Label) immer gleich voll external ist, oder anders gesagt: im ganzen Projekt bekannt. Der implizite Bezug auf den external scope für Funtionen/Variablen, die nicht im jeweiligen File definiert sind, ist dabei genauso wie beim GNU-as. Bei alledem gibt es natürlich auch noch die file-lokalen Definitionen, mit denen ich auch immer wieder gerne herummache. Und die immer wieder die Leute verwirren, weil damit z.B. irgendwelche "unsichtbaren" bss-Benutzungen im map-file auftauchen... Gruß Johannes
Dein IAR ist richtig. Mir ging es um Besonderheiten bei der Bezeichnung "external scope". Ansonsten habe ich das Gefühl, das wir noch seitenweise aneinander vorbeireden könnten. Also lass ich's.
Sorry, iccavr ist nicht IAR. Ansonsten trotz allem Aneinander-Vorbei-Reden nochmal Danke für diese Unterhaltung. Johannes
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.