Forum: Mikrocontroller und Digitale Elektronik Unterschied zwischen STD und STS in asm bei atmel


von micro1 (Gast)


Lesenswert?

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

von D. W. (dave) Benutzerseite


Lesenswert?

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.

von Wolfgang (Gast)


Lesenswert?

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

von Johannes A. (Gast)


Lesenswert?

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

von micro1 (Gast)


Lesenswert?

@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.

von A.K. (Gast)


Lesenswert?

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.

von Michael U. (Gast)


Lesenswert?

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

von Johannes A. (Gast)


Lesenswert?

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

von A.K. (Gast)


Lesenswert?

Und genau so ein "tick" muss "volatile" sein. Alle anderen x*,y*,z*
sind wurscht.

von Johannes A. (Gast)


Lesenswert?

@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

von A.K. (Gast)


Lesenswert?

"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?

von A.K. (Gast)


Lesenswert?

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.

von A.K. (Gast)


Lesenswert?

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.

von Johannes A. (Gast)


Lesenswert?

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

von A.K. (Gast)


Lesenswert?

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.

von Johannes A. (Gast)


Lesenswert?

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

von A.K. (Gast)


Lesenswert?

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.

von Johannes A. (Gast)


Lesenswert?

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

von A.K. (Gast)


Lesenswert?

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.

von Johannes A. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.