Forum: Mikrocontroller und Digitale Elektronik Frage zu Stackpointer - der Sinn


von PC-Anfaenger (Gast)


Lesenswert?

Atmega8, AVR-Studio 4, Simulator2

Viele Beispielprogramme im AVR-Tutorial fangen mit der Initialisierung 
des Stackpointers an:

********************
.CSEG
.org 0
    ldi     r16, low(RAMEND)            ; Stackpointer initialisieren
    out     SPL, r16
    ldi     r16, high(RAMEND)
    out     SPH, r16

*************


Viele Programmbeispiele - z.B. die Beispiele aus dem Kapitel EEPROM 
verwenden doch garkeinen Stack, SPH und SPL werden garnicht dort 
verwendet etc., warum wird das dennoch gemacht? Ich setze nun die 
Adresse im Stackpointer auf RAMEND - wozu?

von 123 (Gast)


Lesenswert?

Ich hab mit AVR nicht viel am hut. Ich kenn auch nicht das tutorial.

Der Stack wird für Funktionsaufrufe verwendet. Springst du in eine 
Funktion muss irgendwo gesichert werden, was vorher in den Registern 
stand, und wo du her kommst. damit der return dann ach wieder richtig 
springt.

Der Stack wird in den Hochsprache für variablen innerhalb einer Funktion 
verwendet.

und der stack wächst bei vielen systemen von oben nach unten. daher 
ramend.

von Hannes L. (hannes)


Lesenswert?

PC-Anfaenger schrieb:
> Ich setze nun die
> Adresse im Stackpointer auf RAMEND - wozu?

Damit Bytes an definierte Stellen auf Stack gelegt werden können und Dir 
nicht die Register, den I/O-Bereich oder andere SRAM-Bereiche mit 
ungewollten falschen Werten füllen.

Schau mal in der Befehlsübersicht nach, welche Befehle den Stack 
benutzen.

Wenn Du ohne Stackpointer auskommen willst, dann solltest Du einen 
AT90S1200, Tiny11, Tiny12 oder Tiny15 benutzen.

...

von radiostar (Gast)


Lesenswert?

Jeder call-Befehl und jeder Interrupt schreibt auf den Stack, damit der 
ret-Befehl dort die Rücksprungadresse findet.

Somit benutzen nur die allereinfachsten Beispielprogramme den Stack 
nicht - diejenigen nämlich, die ohne Subroutinen und Interrupts 
auskommen.

von Karl H. (kbuchegg)


Lesenswert?

PC-Anfaenger schrieb:

> Viele Programmbeispiele - z.B. die Beispiele aus dem Kapitel EEPROM
> verwenden doch garkeinen Stack, SPH und SPL werden garnicht dort
> verwendet etc., warum wird das dennoch gemacht?

Weil es nur ein paar Takte sind, die beim Programmstart benötigt werden 
und dann muss man bei Programmerweiterungen, die einen Stack benötigen 
nicht daran denken, dass man noch einen Stackpointer einrichten muss.

So was nennt man "defensives Programmieren" - mit einplanen, daß ein 
Programmierer auch mal Fehler machen wird und gleich vorausplanen, so 
dass solche Fehler nicht gleich zum Desaster ausarten.

> Ich setze nun die
> Adresse im Stackpointer auf RAMEND - wozu?

Weil der Stack vom Ende des Speichers nach vorne wächst, so man einen 
verwendet.

von Yalu X. (yalu) (Moderator)


Lesenswert?

PC-Anfaenger schrieb:
> Viele Programmbeispiele - z.B. die Beispiele aus dem Kapitel EEPROM
> verwenden doch garkeinen Stack, SPH und SPL werden garnicht dort
> verwendet etc., warum wird das dennoch gemacht?

Jedes dieser Beispiele enthält Unterprogrammaufrufe oder Interrupthand-
ler. Bei beiden wird die Rücksprungadresse auf den Stack gelegt, weswe-
gen dieser richtig initialisiert sein sollte.

von Florian (Gast)


Lesenswert?

Ich dachte immer, dass man sich das bei den neueren AVRs Sparen kann?

von Floh (Gast)


Lesenswert?

Florian schrieb:
> Ich dachte immer, dass man sich das bei den neueren AVRs Sparen kann?

Theoretisch ja, da als Initial Value bereits der richtige Wert (RAMEND) 
drinsteht.
Das gilt jedoch nur für die neueren Chips, daher ist es kein Schaden, es 
einfach generell zu machen (kostet 4 Assemblerbefehle zu 
Programmbeginn).
:-)

von spess53 (Gast)


Lesenswert?

Hi

>Wenn Du ohne Stackpointer auskommen willst, dann solltest Du einen
>AT90S1200, Tiny11, Tiny12 oder Tiny15 benutzen.

Ohne Stackpointer, ja. Aber nicht ohne Stack.

>Viele Programmbeispiele - z.B. die Beispiele aus dem Kapitel EEPROM
>verwenden doch garkeinen Stack, SPH und SPL werden garnicht dort
>verwendet etc., warum wird das dennoch gemacht? Ich setze nun die
>Adresse im Stackpointer auf RAMEND - wozu?

Der Stackpointer wird, ohne das du ihn direkt ansprichst, von 'call', 
'rcall', 'ret', 'push', 'pop, 'reti' und Interrupts (was vergessen?) 
benutzt. Diese Befehle legen Werte auf der Adresse, auf die der 
Stackpointer zeigt, ab und decrementieren den Stackpointer oder 
incrementieren den Stackpointer und holen den Wert, auf den der 
Stackpointer zeigt. Bei einem 'call' wird zum Beispiel die 
Programmadresse des Befehls nach dem 'call' auf dem Stack gespeichert. 
Bei einem 'ret' wird der Programmcounter wieder mit diesem Wert geladen 
und das Programm macht nach dem Call-Befehl weiter.

MfG Spess

von PC-Anfaenger (Gast)


Lesenswert?

Vielen Dank fuer die Vielzahl von Antworten. Betrachte ich einfach mal 
die Befehle push und pop.

Wenn ich also vor dem Aufruf einer Routine einen Register sichern will 
und schribe

push r16

Dann müsste ja - wenn ich den Zeiger zum Ende auf RAMEND lege, bei 
Speichervorgängen der Zähler dekrementiert werden - weil wenn ich ja 
bereits bei RAMEND bin, dann kann ja nichts weiter inkrementiert werden?

Was ist aber, wenn ich den Stack nicht initialisiere? Wenn der dann bei 
"RAMSTART" stehen würde und ich dann etwas speichern würde - und dann 
dekrementieren täte - so dürfte das ja dann nicht gehen?

Also würde es bedeuten, wenn ich nicht die oben vorgestellte 
Initialisierung mache und selber mit .dseg Speicher reserviere, dass es 
dann zu Ueberschneidungen kommt, wenn ich push/pops und andere Spruenge 
mache?

von spess53 (Gast)


Lesenswert?

Hi

>Dann müsste ja - wenn ich den Zeiger zum Ende auf RAMEND lege, bei
>Speichervorgängen der Zähler dekrementiert werden - weil wenn ich ja
>bereits bei RAMEND bin, dann kann ja nichts weiter inkrementiert werden?


Wird er auch. Aus dem Instruction Set:

This instruction stores the contents of register Rr on the STACK. The 
Stack Pointer is post-decremented by 1 after the PUSH.
           ^^^^^^^^^^^^^^^^
>Was ist aber, wenn ich den Stack nicht initialisiere? Wenn der dann bei
>"RAMSTART" stehen würde und ich dann etwas speichern würde - und dann
>dekrementieren täte - so dürfte das ja dann nicht gehen?

Nicht initialisiert zeigt der Stackpointer, je nach AVR, entweder auf 
$0000 oder RAMEND.

>Also würde es bedeuten, wenn ich nicht die oben vorgestellte
>Initialisierung mache und selber mit .dseg Speicher reserviere, dass es
>dann zu Ueberschneidungen kommt, wenn ich push/pops und andere Spruenge
>mache?

Richtig. Und das endet zu 100% in einem Crash.

MfG Spess

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.