Forum: Mikrocontroller und Digitale Elektronik Funktionen mit parameter in Assembler


von Andy11 (Gast)


Lesenswert?

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?

von Grrrr (Gast)


Lesenswert?

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

von Andy11 (Gast)


Lesenswert?

>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

von Grrrr (Gast)


Lesenswert?

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

von Andy11 (Gast)


Lesenswert?

also gibt es da nicht sowas ähnliches wie Klammern zur Parameterübergabe 
sowie in c?

von Er (Gast)


Lesenswert?

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.

von Andy11 (Gast)


Lesenswert?

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

von Grrrr (Gast)


Lesenswert?

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?

von Er (Gast)


Lesenswert?

Im Grunde ist jede compilierende Hochsprache eine Art Makroassembler.

von Grrrr (Gast)


Lesenswert?

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>

von Frank (Gast)


Lesenswert?

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

von Frank (Gast)


Lesenswert?

Grrr war schneller, schöner und besser

von Andy11 (Gast)


Lesenswert?

@GRR
>Kannst Du damit was anfangen?
auf jedenfall, echt starke erklärung, besten dank

@ Frank
dir auch besten dank

lg andy

von Grrrr (Gast)


Lesenswert?

Andy11 schrieb:
> auf jedenfall, echt starke erklärung, besten dank

Biddeschön.

von Grrrr (Gast)


Lesenswert?

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