Hallo,
bin gerade am Assembler lernen... habe folgende Zeilen noch nicht
kapiert.
was ist "RAMED" (oder "FLASHED") und was ist SPL - SPH.
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
Das was ich bis jetzt mit LEDs so getestet habe, hat bis jetzt immer
ohne diese Zeilen Funktioniert...
Achso, bevor ichs vergess .. ich Programiere Mit ATMEL (ATMega8).
Gruß
Axl
RAM = RAM-Speicher
END = Ende von irgendetwas
RAMEND = Letzte Adresse RAM-Speicher
SP = Stackpointer
LOW = untere 8 Bit eines 16 Bit Wertes
HIGH = obere 8 Bit eines 16 Bit Wertes
SPL = Hardware-Register des Stackpointers, niederwertiges Byte
SPH = Hardware-Register des Stackpointers, höherwertiges Byte
Was macht der Code? Ganz einfach: Den Stackpointer auf die letzte
RAM-Adresse initialisieren. Warum die letzte Adresse? Weil der Stack bei
den AVRs, wie bei fast allen Prozessoren, nach unten wächst.
für jedes aufgerufene Unterprogamm wird die Rücksprungadresse des
aufrufenden Programms auf den Stack abgelegt und der Stackpointer um
eine Adresse nach vorn geändert.
Der Stack wächst also vom Ende des Rams nach vorn und kann je nach
benutzter Tiefe mit dort abgelegten Variablen in Konflikt kommen. Es
gibt keine automatischen Schutzmechanismen dagegen, der Programmierer
muß selbst ausrechnen, wieviel Platz der Stack maximal belegt.
Unterprogramme, Interrupts und push-Befehle verändern den Stack.
Wenn im untersten Unterprogramm mit gepushten Variablen noch ein
Interrupt auftritt, wird die maximale Ausdehnung erreicht.
Damit...
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
...initialisierst Du den Stack, indem Du den Stackpointer (16-Bit
I/O-Register SPH:SPL) auf die letzte SRAM-Addresse des Controllers setzt
(beim ATmega8 = 0x4FF). Das muss man einmal beim Programmstart machen,
wenn man Unterprogramme oder Interrupts oder die Befehle 'push' und
'pop' zum SIchern von Registerinhalten verwenden will, also praktisch
immer.
Die Konstanten 'RAMEND', 'SPL' und 'SPH' sind wie alle Konstanten in der
Datei M8DEF.INC definiert, die Du in Dein Programm mittels "include"
einbindest. Tipp: M8DEF.INC Mal in einen Editor laden und studieren.
Weitere Infos zum Stack und Stackpointer findest Du - wie immer - im
Datenblatt des Controllers (hier Kapitel "AVR CPU Core").
hm sind das HIGH(RAMEND), LOW(RAMEND) konstanten, die irgendwo
initialisiert sind (wo möglich eine datei), abhängig vom in diesem fall
RAM des jeweiligen µC ?
bei mir im MSP430 heisst es:
mov.w #300h,SP ; Initialize stack pointe
ich nehme an hier ist es nicht so schön programmiert, da nach 300h ->
768d push's sense ist oder?
mfg
Das holt sich der Kompiler aus der jeweiligen Include-Datei. Die kannst
Du
auch mit einem Texteditor angucken, dann siehst Du, welche Adressen das
jeweils sind.
Sinn der Sache ist, den Stack vor den Daten im RAM zu "schützen". Der
Stack
wächst sozusagen von der "Decke" zum "Fußboden" des RAM. Du bist aber
mit Deinen Daten, die Dein Programm erzeugt auch im RAM, kommst
allerdings
"von unten hoch".
Irgendwann würdest Du sonst dann (wenn genügend Zeug von Dir in den RAM
getan worden ist) von unten am Stack "kratzen" und damit dort abgelegte
Sprungadressen kaputtmachen.
MfG Paul
Wo Stack und Daten abngelegt werden, hängt auch von der verwendeten
Controllerfamilie ab. Grundsätzlich sollte der Stack aber an die höchste
der zur Verfügung stehenden SRAM-Adressen angelegt werden. Es sei denn,
der Hersteller gibt ausdrücklich etwas anderes vor. Das es beim MSP430
mit einem Befehl geht, der AVR derer 4 braucht, liegt zum einen an der
Tatsache, daß der AVR nach einer anderen Architektur aufgebaut ist, zum
anderen daran, daß sich Register beim AVR nur 8-Bit-weise laden lassen.
Übrigens, LOW() und HIGH() sind Spezialkommandos des AVR-Assemblers, die
man in ähnlicher Form auch bei anderen Assemblern findet.
Gruß
Jadeclaw.
max wrote:
> |____________________| FFFF> | DATEN |> |____________________| FFFE> | DATEN |> |____________________| FFFD> .> .> .> |____________________| 0301> | STACK |> |____________________| 0300> | STACK | 02FF> |____________________|> .> .> .>> du meinst also das bild hier , nicht?> jop, bei mir würde die daten irrgendwann den stack verschlingen ^^
Naja, ich würde mal eher so sagen:
|____________________| 0000
| DATEN |
|____________________| 0001
| DATEN |
|____________________| 0002
\/
.
.
.
/\
|____________________| FFFD
| STACK |
|____________________| FFFE
| STACK |
|____________________| FFFF (bzw. letzte RAM Adresse)
Und der Vollständigkeit halber sei noch gesagt, dass bei den PICs der
Stack einen eigenen Speicherbereich belegt. Er hat dort die Breite des
Programcounters, also 12, 14 oder 16 Bit. Bei den 16F Typen ist der
Stack allerdings nur 8 Ebenen tief und es gibt keine PUSH und POP
Befehle. Man kann also keine Werte manuell auf den Stack legen. Er dient
ausschließlich der Ablage der Sprungadressen. Bei den 18F hat man den
Stack auf 32 Ebenen erhöht und den Befehlssatz u.a. um PUSH und POP
erweitert. Auch hat man STATUS-Bits eingeführt, welche das Überlaufen
des Stacks anzeigen. Initialisieren muss man bei den PICs den Stack aber
nicht.
Gruß
Sven
Es geht hier doch gar nicht um schneller oder billiger oder was ist
besser. Was soll das nur immer dieses herumgehacke?
Das Thema dreht sich doch um den Stack und ging allmählich in die
Richtung der Grundlagen des Stacks und wie dies auf verschiedenen µC
geamacht wird. Ich wollte nur für den OP mal erklären, dass es auch noch
andere Techniken gibt. Egal ob diese nun besser oder schlechter sind.
Da der OP aber scheinbar eh nicht mehr mit ließt, ist es auch egal. Ich
denke die meisten hier wissen wie der Stack auf ihrer gewählten
Plattform funktioniert. Und der Rest sollte es nach dem Lesen dieses
Threads wissen.
Sven