Guten Tag. Habe das Problem das ich mit bei Assembler daher das ich grad erst angefangen habe erstmal ein 64er Lauflicht gebaut habe und er bei diesem immer sagt: "AVR Simulator: Stack pointer below start of RAM" Das Programm lautet: ;Test .include "m8def.inc" ; AtMega8 laden .def temp1 = r16 ; Register r16 als temp1 benennen .def temp2 = r17 ; Register r17 als temp2 benennen .def temp3 = r18 ; register r18 als temp3 benennen rjmp Reset Reset: ldi temp1, 0xFF ; Register temp1 mit 0xFF beschreiben ldi temp2, 0x01 ; Register temp2 mit 0x01 beschreiben ldi temp3, 0xFE ; Register temp3 mit 0xFE beschreiben out DDRB, temp1 ; Ausgangsregister DDRB mit 0xFF out DDRD, temp1 ; Ausgangsregister DDRD mit 0xFF Loop: out PORTD, temp3 ; Über PORTD Inhalt von temp3 ausgeben out PORTB, temp2 ; Über PORTB Inhalt von temp2 ausgeben lsl temp2 ; 0 in Ihnalt von temp2 einschieben brcs Zeile ; wenn C Flag 1, Zu Prog. Zeile springen ldi temp1, 0x01 ; Register temp1 mit 0x01 beschreiben rcall Warte ; Zu Prog. Warte springen Zeile: ldi temp2, 0x01 ; Register temp2 mit 0x01 beschreiben rol temp3 ; 1 in Inhalt von temp3 einschieben brcc Reset ; wenn C Flag 0, zu Prog. Reset springen rjmp Loop ; Zu Prog. Loop springen Warte: dec temp1 ; Inhalt von temp1 um 1 veringern nop ; einen Tackt nichts tun brne Warte ; wenn Z Flag 0, zu Prog. Warte springen rjmp Loop ; Zu Prog. Loop springen Und der Curser steht in diesem Fall immer auf "dec temp1" Währe nett wenn mir jemand helfen könnte. (Ggf. auch sagen wie ich den Code in eine Extra Box lege, sodass ich es nachträglich bearbeiten kann.)
Gast
#1898923
Ich glaube nicht, dass das für so ein Minimalprogramm, was keine Interrupts enabled (kein "sei" hinter "Reset:") und keine rcall-Aufrufe macht, so etwas braucht, aber jedes Programm, was über ein Ansteuern einer LED hinaus geht, muss am Anfang den Stack-Pointer initialisieren: Reset: ldi r16,high(RAMEND); Main program start out SPH,r16 ; Set Stack Pointer to top of RAM ldi r16,low(RAMEND) out SPL,r16 (Mich wundert nur, dass der Simulator da moppert.)
Gast
#1898925
Hi Dir fehlt die Stack-Initialisierung:
1 | |
2 | |
3 | |
4 | |
Sollte als erstes gemacht werden. MfG Spess
wenn du WARTE: per rcall aufrufst, so muss dies auch mit RET wieder beendet werden, und nicht per RJMP! Sonst ist der STACK schnell voll! Sascha
Reicht es wenn ich diese Initialisierung nur einmal mache oder muss der da dauernt drüber laufen? Verstehe das Kapitel Stack aus dem Tutorial leider nicht so ganz ... Hab grad auch nochmal ein wenig mit Rumversuchen versucht, kriege es aber irgendwie nicht hin ... Habe anstatt r16 r19 genommen, falls das wichtig sein sollte.
Gast
#1898944
Hi >Reicht es wenn ich diese Initialisierung nur einmal mache oder muss der >da dauernt drüber laufen? Nein, nur ein mal. Den Rest macht der Controller. MfG Spess
Hmm .. habe nun das mit dem Stack eingebastelt wie hier geschrieben und das rcall Loop durch ret ersetzt. Nur irgendwie funktioniert das nichtmehr so wie vorher. Vorher hatte ich es so das ich PORTB die X Achse und PORTD die Y Achse einer LED Matrix anschließen konnte und ich ein Lauflicht hatte. Nun ist es so das die X Achse Läuft und die Y Achse aber immer einer mehr leuchtet ... ;Test .include "m8def.inc" ; AtMega8 laden .def temp1 = r16 ; Register r16 als temp1 benennen .def temp2 = r17 ; Register r17 als temp2 benennen .def temp3 = r18 ; Register r18 als temp3 benennen .def Stack = r19 ; Register r19 als Stack benennen ldi Stack,high(RAMEND) out SPH,Stack ldi Stack,Low(RAMEND) out SPL,Stack rjmp Reset Reset: ldi temp1, 0xFF ; Register temp1 mit 0xFF beschreiben ldi temp2, 0x01 ; Register temp2 mit 0x01 beschreiben ldi temp3, 0xFE ; Register temp3 mit 0xFE beschreiben out DDRB, temp1 ; Ausgangsregister DDRB mit 0xFF out DDRD, temp1 ; Ausgangsregister DDRD mit 0xFF Loop: out PORTD, temp3 ; Über PORTD Inhalt von temp3 ausgeben out PORTB, temp2 ; Über PORTB Inhalt von temp2 ausgeben lsl temp2 ; 0 in Ihnalt von temp2 einschieben brcs Zeile ; wenn C Flag 1, Zu Prog. Zeile springen ldi temp1, 0x01 ; Register temp1 mit 0x01 beschreiben rcall Warte ; Zu Prog. Warte springen Zeile: ldi temp2, 0x01 ; Register temp2 mit 0x01 beschreiben rol temp3 ; 1 in Inhalt von temp3 einschieben brcc Reset ; wenn C Flag 0, zu Prog. Reset springen rjmp Loop ; Zu Prog. Loop springen Warte: dec temp1 ; Inhalt von temp1 um 1 veringern nop ; einen Tackt nichts tun brne Warte ; wenn Z Flag 0, zu Prog. Warte springen ret ; Zu Prog. Loop springen Villeicht kann das ja jemand mal Simulieren ... ich nutze AVRStudio4. Info am Rande: Die Fehler zeigt er nur wenn ich auf "Run" gehe, nicht aber wenn ich auf "Auto Step" gehe (ausser bei dem mit ret da zeigt er den extra genannten Fehler bei beiden Varianten).
Gast
#1898986
So kannst Du Dir das rjmp Reset auch sparen. Versuche nicht zu frunzeln bis es geht, sondern versuche erst mal zu verstehen, was Du machst. Dieses "rjmp Reset" ist eigentlich nur in Programmen nötig, die mit Interrupts arbeiten, weil ganz vorne die Interrupt-Tabelle liegt, deren erster Eintrag der Reset-Handler ist. Normalerweise sieht ein Programmanfang auf einem ATmega8 so aus:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
Du brauchst das alles nicht, da Du kein "sei" brauchst, bis Du anfängst, das Lauflicht durch einen der Timer zu steuern. Solange Du aber keinen Stack hast, kanst Du keine Unterprogramme (Warte) benutzen, was in diesem Fall einfach durch Verschieben des entsprechenden Codes an die Stelle seines Aufrufs gelöst werden kann.
Wie nutze ich so einen Timer? Habe es so gemacht wie ich es verstanden habe. Und daher das manche Dinge häufig und nur in bestimmten Situtationen abgerufen werden habe ich mir Unterprogrammen gearbeitet. Bekomme es irgendwie nicht zum laufen und zusätzlich hat er plötzlich PIND ein Low wo an PORTD ein Low ist .... wie geht das? ^^
Gast
#1898991
Hi >SPM_RDY: > iret Besser 'reti' MfG Spess
spess53 schrieb: >>SPM_RDY: > >> iret > > > > Besser 'reti' Kann zufällig jemand die Begriffe erklären .. ^^ (Bedeutung Funktion). Will schon auch verstehen und nicht nur Copy and Paste machen ^^. Wenn ich alle rcall in meinem Programm durch rjmp ersetze funktinierts .. was ist der Unterschied zwischen diesen beiden befehlen? Zudem wollte ich nochmal gerne fragen ob man während das Prog. auf "run" steht irgendwie die Zustände der Aus/Eingänge sehen kann.
Gast
#1899008
Hi >Kann zufällig jemand die Begriffe erklären .. ^^ (Bedeutung Funktion). Welche? Wenn du rjmp RESET ; Reset Handler rjmp EXT_INT0 ; IRQ0 Handler ... meinst. Das findest du im Datenblatt unter Interrupts. 'reti' und alle anderen Befehle in der Hilfe zum Assembler vom AVR-Studio unter 'Instructions' oder hier www.atmel.com/atmel/acrobat/doc0856.pdf MfG Spess
Gast
#1899028
Bei RET wird zur Zeile nach dem RCALL gesprungen. Das heißt das Programm macht bei ZEILE weiter nicht bei LOOP!
Wenn ich ret eingebe springt er irgendwie immer zum ersten rjmp .. Also zum Anfang des Programms.
Gast
#1899118
Bei rcall wird die Adresse für den Rücksprung in den Stack geschrieben. Bei ret wird die Adresse vom Stack geholt und dahin Gesprungen. Dem ret ist es egal ob im Stack an der Position eine Adresse steht, er versucht trotzdem dahin zu Springen und kann irgendwo im Programm Landen!
Wenn ich richtig verstanden habe geht dies ret also nur wenn ich "rcall" gemacht habe, aber nicht bei "brcc" oder "brne"
Gast
#1899239
spess53 schrieb: > Hi > >>SPM_RDY: >> iret > > Besser 'reti' > > MfG Spess Äh ja. peinlichgrins Das war x86er Assembler.
Was war das? .... Meinst jetzt dass das für AVR mit 32Bit war?
Gast
#1899261
Hi >Wenn ich richtig verstanden habe geht dies ret also nur wenn ich "rcall" >gemacht habe, aber nicht bei "brcc" oder "brne" Richtig. 'rcall' und bei größeren AVRs auch 'call' springen zu dem dahinter stehenden Label. Gleichzeitig wird die Adresse des nachfolgenden Befehls auf dem Stack gespeichert. Beim Erreichen des 'ret' holt sich der Controller diese Adresse wieder vom Stack und macht an der o.g. Stelle weiter. Bei 'brxx', 'rjmp' und 'jmp' wird keine Adresse auf dem Stack gespeichert. Also kann auch ein 'ret' nichts sinnvolles vom Stack holen. MfG Spess
Gast
#1899320
> Wenn ich richtig verstanden habe geht dies ret also nur wenn ich "rcall" > gemacht habe, aber nicht bei "brcc" oder "brne" Ja, genau. Ich habe das Gefühl, Dir ist das Konzept eines Stacks noch nicht so ganz klar. Der Stack ist ein Stapelspeicher, wie ein Stapel Teller. Du legst einen Teller A drauf, dann einen Teller B. Wenn Du die Teller wieder herunter nimmst, kommt zuerst Teller B, dann Teller A. Hier sind es jedoch keine Teller, sondern Bytes, die auf dem Stack abgelegt werden. Wenn mit "rcall" ein Unterprogramm aufgerufen wird, wird die aktuelle Stelle, an der das Programm gerade ist, also 2 Bytes, auf dem Stack abgelegt, und dann wird zu der Adresse des Unterprogramms gesprungen. Am Ende des Unterprogramms wird der oberste Teller vom Stapel genommen, und dorthin zurück gesprungen. Der Befehl für beide Aktionen ist "ret". Ein "reti" macht im Prinzip dasselbe, nur wird das Flag, das Interrupts erlaubt, dabei gesetzt. Der Stack wird repräsentiert durch den Stack-Zeiger, also einem Register, in dem die Adresse des nächsten freien Platzes auf dem Stack steht. Das bemerkenswerte bei diesem Stack ist, das die Teller quasi an der Decke hängen, also der Stack am oberen Ende des Speichers anfängt, und nach unten wächst. Deswegen die Initialisierung mit "RAMEND" (Ende des RAM) am Anfang. Der Stack wird aber nicht nur Rücksprungadressen verwendet, sondern auch, um Werte zu sichern und sie später zu restaurieren. Mit "push r1" legst Du den Inhalt des Wertes vom Register r1 auf dem Stack ab, mit "pop r1" kannst Du dann den Wert wieder vom Stack holen. Das macht besonders in Unterprogrammen Sinn, die durch Interrupts aufgerufen werden, weil diese keine Register verändern dürfen, die woanders, also möglicherweise in einem unterbrochenen Programmteil, gerade benutzt werden. > Was war das? .... Meinst jetzt dass das für AVR mit 32Bit war? Nein, das war für 80x86 CPUs, wie sie auf PCs Verwendung finden. Der erste Proz, für den ich (in den 80ern) Assembler programmiert habe, war ein 8086. Irgendwie bleibt das haften und drängt immer wieder nach außen. :-D
Ok .. wenn ich das alles nun richtig Verstanden habe war meine Aktion das ich alle rcall durch rjmp ersetzt habe richtig, da ich immer am Ende der unterprogramm Resete (Ganz von vorne anfange) oder Ein anderes Unterprogramm/Hauptprogramm von vorne anfange. Der Stack speichert bei einem rjmp die aktuelle Position sodass wenn man ret eingibt er automatisch zu dieser Position zurückspringt und den nächsten Befehl ausführt, welcher danach gekommen währe. Zum Thema reti: Bei Interrupts bin ich nochnicht ^^. Und zu dem mit dem pop und Push wollte ich nochmal frgaen: Wenn ich Push genutzt habe dann kann ich aber kein ret mehr nutzen bis ich wieder ein rcall hatte oder?
Michael Dierken schrieb: > Ok .. wenn ich das alles nun richtig Verstanden habe war meine Aktion > das ich alle rcall durch rjmp ersetzt habe richtig, da ich immer am Ende > der unterprogramm Resete (Ganz von vorne anfange) oder Ein anderes > Unterprogramm/Hauptprogramm von vorne anfange. ja > Der Stack speichert bei einem rjmp die aktuelle Position sodass wenn man > ret eingibt er automatisch zu dieser Position zurückspringt und den > nächsten Befehl ausführt, welcher danach gekommen währe. nein der Stack speichert bei einem rcall o. call die 'Position' > Zum Thema reti: Bei Interrupts bin ich nochnicht ^^. > > Und zu dem mit dem pop und Push wollte ich nochmal frgaen: Wenn ich Push > genutzt habe dann kann ich aber kein ret mehr nutzen bis ich wieder ein > rcall hatte oder? ähm?! du kannst ein ret vor einem rcall/call aufrufen, aber das hat nichts mit push/pop zu tun Wenn du mit rcall in ein Unterprogramm springst und dort push benutzt, dann must du vor dem ret erst pop benutzen. Ebensowenig kannst du erst push benutzen, dann mit rcall springen und dann pop benutzen. Du hast die Funktion des Stack definitiv noch nicht verstanden. Sascha
Gast
#1900270
Hi >Ok .. wenn ich das alles nun richtig Verstanden habe war meine Aktion >das ich alle rcall durch rjmp ersetzt habe richtig, da ich immer am Ende >der unterprogramm Resete (Ganz von vorne anfange) Nein. Ein Reset als Folge eines 'ret' ist ein Programmabsturz! Außerdem passiert das nur bei einem leeren Stack. Wenn sich etwas auf dem Stack befindet geht das irgendwo ins Nirvana. Also: rcall label ... ... label: ... ... ... ret >Der Stack speichert bei einem rjmp die aktuelle Position sodass wenn man >ret eingibt er automatisch zu dieser Position zurückspringt und den >nächsten Befehl ausführt, welcher danach gekommen währe. Nein. Das passiert bei rcall/call. >Und zu dem mit dem pop und Push wollte ich nochmal frgaen: Wenn ich Push >genutzt habe dann kann ich aber kein ret mehr nutzen bis ich wieder ein >rcall hatte oder? Nein. Wenn du in einem Unterprogramm ein oder mehrere Register auf den Stack 'gepusht' hast müssen die vor dem 'ret' wieder mit 'pop' vom Stack geholt werden: Label: push r16 push r17 ... ... pop r17 pop r16 ret MfG Spess
Gast
#1900329
Hallo Michael Ich glaube dir ist am besten geholfen, wenn man dir rät zuerst das Tutorial abzuklappern. Mir hat das am Anfang am meisten gebracht, die Themen einzeln und möglichst kurzschrittig auf einem Steckbrett nachzuvollziehen und dann Änderungen im Code dazuzubasteln. Dadurch kannst du selbst sehen welche effekte die änderungen haben - du hast aber ein funktionierendes Programm als Ausgangspunkt. Außerdem steht ganz viel nützliches Zeug im Datenblatt und es gibt auch eine asm-Befehlsreferenz von Atmel im Netz (die hatte ich mir damals ausgedruckt(!)). Ich wünsche dir viel Erfolg und Freude beim "lernen" Robert (seit 2 Jahren kein Anfänger mehr - aber noch lange kein Profi:))
Sascha Weber schrieb: > Du hast die Funktion des Stack definitiv noch nicht verstanden. Deswegen frage ich ja nochmal ^^. Habe ausversehen vorhin rjmp und rcall vertauscht .. meinete natürlich das er bei rcall speichert. Zu iche (Gast): Ja ich mache grad das Tutorial, aber überwiegend Theoretisch, da die Hardware nochnicht da ist und da habe ich dann einfach mal versucht soweit wie ich war mir ein 64Kanal Lauflicht zu basteln ^^. Vielen Dank für eure Geduldigen Antworten. Auch wenn ich das mit push und pop nochnicht ganz verstehe: Wenn ich dies Push mache, muss ich danach einfach nur das pop mit dem gleichen Register machen? So wie ich es zuvor verstanden habe kann man mit den push (Wert im Register des Stack ablegen) da was reinschreiben was aber ja nicht mit pop (Auslesen) wiederkommen würde.
Gast
#1900410
push und pop haben nicht viel mit dem register zu tun auf welches sie zugreifen/lesen mit push schiebst du den inhalt des registers R (egal welches - du musst halt eins nehmen) oben als letzten wert auf den stack und mit pop lädst du den letzten wert auf dem stack in das register R". R und R" können, müssen aber nicht das gleiche sein.
Gast
#1900414
wenn du
1 | |
2 | |
3 | |
4 | |
machst, vertauschst du die inhalte der register r16 und r17 ;-)
Meinst du mit R und R" sowas wie z.B. rr16 und r17? Denke das ich den sinn so langsam kapiert habe .. muss mal ein wenig rumprobieren, ggf. kommt das auchnicht im Tutorial ^^.
Gast
#1900418
ja genau
Eine letzte Frage noch: Sehe ich das richtig das man max. 16Bit auf dem Stack ablegen kann?
Gast
#1900437
eigentlich kannst du immer nur 8bit (selbst) im sram (der stack befindet sich im sram) ablegen. wie der SRAM genau aufgebaut ist, hab ich jetzt nicht auf die schnelle gefunden (steht nicht direkt im datenblatt) So aus dem Tutorial habe ich: SRAM 8bit - bei uC mit mehr als 256Byte ram is der adresszähler dann natürlich breiter als 8bit (sonst könnte ja die adresse $257 nie erreicht werden. und wenn du 16/32/64 Bit auf dem Stack/Sram ablegen willst, musst du die bytes eben alle nacheinander (in der richtigen reihenfolge) aufn Stack / innen Sram packen. aber bitte: fang klein und vor allem möglichst weit vort im tutorial an - dann entstehen solche grundsatzlichen fragen nicht, und ich schreibe mich nicht so in rage, dass ich gleich die groß-KLEINschreibung vergesse^^
Michael Dierken schrieb: > Eine letzte Frage noch: Sehe ich das richtig das man max. 16Bit auf dem > Stack ablegen kann? Du kannst auf dem Stack ablegen soviel du willst und solange der dafür notwendige Speicher noch frei ist. Am einfachsten macht man sich das Konzept eines Stacks (wieder mal) mit Papier und Bleistift klar. Das weiter oben genannte Beispiel mit den Tellern war schon nicht schlecht, trifft es aber konkret nicht so recht Angenommen wir haben diesen Code (die Zahlen in der linken Spalte geben an, wo genau im Speicher diese Anweisung durch den Assembler abgelegt wurde. In deinem Programmtext sind sie nicht vorhanden. Ich habe sie nur ergänzt um mich im Code auf etwas beziehen zu können
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
der Stack sei symbolisiert, durch eine Spalte am rechten Bildschirmrand.
Wir wollen mal sehen, wie sich der entwickelt. Der Stackpointer sei
dabei ein Pfeil.
das Programm beginnt, der Stack wird initialisiert (nicht weiter
gezeigt) und irgendwann landet das Programm an der Adresse 0100
Hier ist der Stack
+------+
-->| |
+------+
die erste Anweisung1 | |
Register 16 wird mit 0xAA geladen, das hat keine Auwirkungen auf den
Stack, wir merken uns aber, dass in r16 0xAA steht
r16 r17 r18 +------+
+------+ +-------+ +-------+ -->| |
| AA | | | | | +------+
+------+ +-------+ +-------+
1 | |
r16 r17 r18 +------+
+------+ +-------+ +-------+ -->| |
| AA | | 55 | | | +------+
+------+ +-------+ +-------+
1 | |
der Assembler hat schon dafür gesorgt, dass anstelle von do_it die
Adresse von do_it (0200) eingesetzt wurde. Für den Prozessor steht da
also ein Aufruf eines Unterprogrammes, das an der Stelle 0200 beginnt.
Damit beim ret wieder zum Aufrufer zurückgefunden wird, wird die
aktuelle Adresse der Ausführung (die schon durch die Befehlsverarbeitung
auf den Befehl nach den rcall gesetzt wurde) auf dem Stack gesichert.
der rcall steht auf Adresse 0104, der nächste Befehl steht auf 0106
nach Abarbeitung des rcall ist die Situation also so
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| AA | | 55 | | | +------+
+------+ +-------+ +-------+ | 01 |
+------+
-->| |
+------+
Auf dem Stack wurde die Adresse 0106 (in 2 Happen) abgelegt und die
Programmausführung geht bei 0200 weiter.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
die nächste Anweisung ist
1 | |
r17 hat den Inhalt 55 und der wird als nächstes auf den Stack gepusht.
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| AA | | 55 | | | +------+
+------+ +-------+ +-------+ | 01 |
+------+
| 55 |
+------+
-->| |
+------+
1 | |
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| AA | | 55 | | | +------+
+------+ +-------+ +-------+ | 01 |
+------+
| 55 |
+------+
| AA |
+------+
-->| |
+------+
1 | |
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| AA | | 55 | | 02 | +------+
+------+ +-------+ +-------+ | 01 |
+------+
| 55 |
+------+
| AA |
+------+
-->| |
+------+
1 | |
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| AA | | 55 | | 02 | +------+
+------+ +-------+ +-------+ | 01 |
+------+
| 55 |
+------+
| AA |
+------+
| 02 |
+------+
-->| |
+------+
1 | |
pop ist die Umkehrung vom push. Das unterste (konzeptionell das zuletzt
abgelegte) Byte wird in das angegebene Register geholt. Hier ist das
jetzt 02, welches ins Register r16 geholt wird. Gleichzeitig wird dieses
Element auch vom Stack insofern entfernt, als der Stackzeiger sich
wieder um 1 Byte zurückbewegt. Dadurch werden zwar die 02 nicht aus dem
Speicher gelöscht, aber konzeptionell ist es 'nicht mehr auf dem Stack
vorhanden'.
Nach dem pop r16 sieht die Situation also so aus
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| 02 | | 55 | | 02 | +------+
+------+ +-------+ +-------+ | 01 |
+------+
| 55 |
+------+
| AA |
+------+
-->| |
+------+
1 | |
wieder: das letzte Byte am Stack wird nach r17 geholt
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| 02 | | AA | | 02 | +------+
+------+ +-------+ +-------+ | 01 |
+------+
| 55 |
+------+
-->| |
+------+
1 | |
r16 r17 r18 +------+
+------+ +-------+ +-------+ | 06 |
| 02 | | AA | | 55 | +------+
+------+ +-------+ +-------+ | 01 |
+------+
-->| |
+------+
und damit ist dann im nächsten Befehl der ret erreicht
1 | |
ret holt sich die letzten beiden Bytes vom Stack (wie auch immer die dorthin gelangt sind) und nimmt sie als Adresse an der die Programmausführung fortgesetzt werden soll. In diesem Beispiel sind die beiden letzten Bytes 01 und 06. Zusammengesetzt ergibt das die Adresse 0106 und dort geht dann die Programmausführung nach dem ret weiter. Und wenn du dir jetzt das ursprüngliche Programm ansiehst
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
dann ist 0106 genau die Adresse an der die nächste Anweisung nach dem rcall steht, der den Unterprogrammaufruf (und damit das Ablegen von 0106 auf dem Stack) ausgelöst hat. Und ja. Wenn wir im Unterprogramm einen pop zuwenig gemacht hätten, dann hätte sich der ret ganz andere Bytes vom Stack geholt, weil dann 1 Byte am Stack übrig geblieben wäre und damit der ret sich etwas völlig Falsches vom Stack geholt hätte. In Assembler gibt es hier keinerlei Überprüfung. Du pusht etwas auf den Stack, du popst etwas vom Stack. Was, wieviel, in welche Register: das ist dein Bier. Niemand redet dir da drein. Und schon gar nicht der Prozessor. Push, Pop, Rcall, Ret all diese Befehle interessiert nicht was vorher war. Ihr Verhalten ist genau festgelegt und dreht sich nur darum ob ein Byte auf den Stack kommt, ein Byte vom Stack genommen wird, bzw. ob bei einem Aufruf etwas auf den Sttack geschrieben wird oder beim Ret wieder vom Stack geholt wird. Das das alles zusammenstimmt ... darum musst du dich als Programmierer kümmern.
Gast
#1900642
@Michael Du kannst das doch alles mal im Simulator (AVR-Studio) nachvollziehen, dann hast Du es kappiert. Mach doch mal ein push und pop im Einelschritt-Modus, schau Dir die Register und den Stack an etc. Und dann die Beispiele von K. H. Buchegger, spess53 und den anderen.
Gast
#1901079
Erstmal an Karl Heinz Buchegger: Respekt ... wie lange hast daran geschrieben ^^. Denke das ich es nun nach dem Beispiel von K. H. B. kurz Mod verstanden habe und werde es nochmal wie von Frank angesprochen nochmal im Einzelschritt anschauen.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.