ich finde das nirgends. Kann ich sowas übrhaupt in Assembler machen=? wenn ja, weiß da einer eine gute Seite wo ich ne Anleitung dazu finde?
Nun, wenn Du schon Assemblerprogramme geschrieben hast kannst Du es in "Funktionen" genauso machen. (Der Begriff passt hier nicht ganz, aber lassen wir das mal gut sein). 1. Speicher (also eine ggf. benannte Adresse einer Variablen) 2. Stack (also Offset zum gegenwärtigen Stackzeiger) 3. Register
>1. Speicher (also eine ggf. benannte Adresse einer Variablen) >2. Stack (also Offset zum gegenwärtigen Stackzeiger) >3. Register ich weiß zwar was diese ganzen sachen da sind was du aufgezählt sind, jedoch sehe ich noch keine struktur sprich: ich werd dadurch nicht schlauer
Andy11 schrieb:
> jedoch sehe ich noch keine struktur
Was heisst: Struktur in diesem Zusammenhang?
Du rechnest mit Werten aus
1. dem Speicher
2. dem Stack (also Offset zum gegenwärtigen Stackzeiger)
3. einem Register
also gibt es da nicht sowas ähnliches wie Klammern zur Parameterübergabe sowie in c?
Welchen Assembler benutzt du denn?(ist nicht ganz unwichtig) Schau dir mal die Makrofähigkeiten deines Exemplares an, damit kann man schon eine ganze Menge anstellen.
>Welchen Assembler benutzt du denn? Assembler in AVR Studio 4.18 >Schau dir mal die Makrofähigkeiten deines Exemplares an, damit kann man >schon eine ganze Menge anstellen. wie ich hier gerade sehe http://www.mikrocontroller.net/articles/AVR_Assembler_Makros das ist ja schon fast c oder?
Andy11 schrieb: > also gibt es da nicht sowas ähnliches wie Klammern zur Parameterübergabe > sowie in c? Nein. Denke daran, das der Prozessor nur und ausschliesslich Assembler versteht. Ich meine im AVR-Assembler hat das runde Klammerpaar keine Bedeutung. Du musst also die Bedeutung (die Semantik) der Klammer in Assembler nachbilden. Das macht auch der C-Compiler. Dazu gibt es die genannten Wege. Assembler-Makros sind nicht ganz das was man als Analogon von Funktionen in Assembler betrachtet. Sie machen nur Textersatz (ähnlich wie der C-Preprozessor). Aber jedesmal wenn Du ein Makro verwendest wird der ganze Assemblertext eingesetzt. Es wird keine Subroutine erzeugt und auch kein call oder ret. Hmmm. Vielleicht war meine erste Antwort ein wenig zu lakonisch für einen Anfänger aber ich wusste ja auch nicht wie weit Du schon bist. Also nehmen wir mal an, wir reden von einem AVR Prozessor und dein erster Befehl in dem Unterprogramm, der tatsächlich was für Deine Anwendung tut, ist ein ADDIW <Register>, <Literal> Wie bekommst Du nun Deinen "Parameter" in das Register? Dazu gibt es die drei Möglichkeiten. Fangen wir mit der einfachsten an 3. Register D.h. Du legst also für Dich selbst und für das Unterprogramm fest, das der Parameter in einem bestimmten Register steht, wenn das Unterprogramm per call aufgerufen wird. Der nächst komplexere Fall ist 2. Stack Dann musst Du festlegen an welcher Position relativ zum gegenwärten Stackzeiger der entsprechende Wert steht. Sagen wir er steht 4 Byte unter dem Stackzeiger. Dann musst Du also den Stackzeiger nehmen und erstmal in ein freies Register laden damit Du damit rechnen kannst. Abgesehen davon das Du mit dem Stackzeiger beim AVR nicht direkt rechnen kannst, soll der Stackzeiger ja so bleiben wie er ist. Z.B. wenn noch mehr Parameter auf dem Stack sind. Letzlich aber muss beim ret der Stackeiger stimmen, damit wieder an die Stelle des Aufrufs zurückgekehrt werden kann. MOVW <Hilfsregister>, <Stackzeiger> Dann subtrahierst Du den Offset Deines Parameters davon SUBIW <Hilfsregister>, <Offset> ; Der war ja hier 4 OK. Jetzt habe wir die Adresse des Parameters im RAM (und innerhalb des Stackbereiches, wenn wir alles richtig gemacht haben). Nun müssen wir noch die Daten von der Adresse in das Register laden das wir anschliesend mit dem ADIW Befehl verwursten wollen. LDD <Register>, <Hilfsregister> ; Das Hilfsregister enthält jetzt die Adresse Voilà 1. Speicher OK. Jetzt kommt der dritte Weg und der ist ein wenig schwieriger. Aber er baut auf der 2ten Lösung auf. Das besondere ist, das wir gleichzeitig die Möglichkeit erhalten den Wert nicht nur innerhalb der Funktion zu verwenden sondern den Parameter dauerhaft zu verändern. D.h. die Änderung ist auch noch vorhanden wenn die Subroutine wieder verlassen wird. Wir übergeben nämlich jetzt nicht den Wert selbst auf dem Stack sondern seine Adresse im RAM. Eine RAM-Variable. Ganz normal. OK. Auf dem Stack ist also jetzt die Adresse wieder 4 Bytes unter dem aktuellen Stackzeiger. Jetzt laden wir erstmal wieder den aktuellen Stackzeiger und holen uns den Wert der dort steht, der aber nun erstmal nur die Adresse des eigentlichen Variablenwertes ist MOVW <Hilfsregister>, <Stackzeiger> SUBIW <Hilfsregister>, 4 ; immer schön an den Offset denken LDD <2.Hilfsregister>, <Hilfsregister> Im 2. Hilfsregister steht jetzt der Wert und im ersten (was ich nur Hilfsregister genannt habe) die Adresse. Am Ende könnten wir jetzt den veränderten Wert mit Hilfe der Variablenadresse im 1. Hilfsregister wieder zurückspeicher. Das muss natürlich vor dem ret passieren. STD <Hilfsregister>, <Register> Kannst Du damit was anfangen?
Im Grunde ist jede compilierende Hochsprache eine Art Makroassembler.
Mist. Im dritten Fall ist mir was unter den Tisch gefallen. Er muss so lauten: 1. Speicher OK. Jetzt kommt der dritte Weg und der ist ein wenig schwieriger. Aber er baut auf der 2ten Lösung auf. Das besondere ist, das wir gleichzeitig die Möglichkeit erhalten den Wert nicht nur innerhalb der Funktion zu verwenden sondern den Parameter dauerhaft zu verändern. D.h. die Änderung ist auch noch vorhanden wenn die Subroutine wieder verlassen wird. Wir übergeben nämlich jetzt nicht den Wert selbst auf dem Stack sondern seine Adresse im RAM. Eine RAM-Variable. Ganz normal. OK. Auf dem Stack ist also jetzt die Adresse wieder 4 Bytes unter dem aktuellen Stackzeiger. Jetzt laden wir erstmal wieder den aktuellen Stackzeiger und holen uns den Wert der dort steht, der aber nun erstmal nur die Adresse des eigentlichen Variablenwertes ist MOVW <Hilfsregister>, <Stackzeiger> SUBIW <Hilfsregister>, 4 ; immer schön an den Offset denken LDD <2.Hilfsregister>, <Hilfsregister> Im 2. Hilfsregister steht jetzt die Adresse der Variablen im Speicher. Mit einem weiteren LDD laden wir jetzt den eigentlichen Wert in unser Register. LDD <Register>, <2.Hilfsregister> Voilà! Am Ende könnten wir jetzt den veränderten Wert mit Hilfe der Variablenadresse im 1. Hilfsregister wieder zurückspeicher. Das muss natürlich vor dem ret passieren. STD <Hilfsregister>, <Register>
mit >1. Speicher (also eine ggf. benannte Adresse einer Variablen) >2. Stack (also Offset zum gegenwärtigen Stackzeiger) >3. Register ist gemeint, das die parameterübergabe so stattfinden kann: zu 1. - parameter in einen speichplatz kopieren - funktion aufrufen - parameter von dem speichplatz holen zu 2. das selbe nur über den stack - parameter auf dem stack legen (push) - funktion aufrufen - parameter vom stack holen (pop) zu 3. register ist jetzt wohl klar, die parameterübergabe findet über ein oder mehrere register statt
@GRR
>Kannst Du damit was anfangen?
auf jedenfall, echt starke erklärung, besten dank
@ Frank
dir auch besten dank
lg andy
Andy11 schrieb:
> auf jedenfall, echt starke erklärung, besten dank
Biddeschön.
Eine weiter Kleinigkeit, die aber relevant ist. Ich habe vergessen, das beim AVR der Stack von hohen zu niedrigen Adressen "wächst". Bei jedem Push wird der Stackzeiger verringert und bei jedem Push wieder erhöht. Entsprechend muss der Offset addiert werden und nicht subtrahiert. Ist halt bei verschiedene Architekturen auch verschieden. Deswegen ist mir das passiert. Sorry.
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.