Nein. Du vergisst, dass "rcall Unterprogramm" die Rücksprungadresse für das "ret" auf den Stack packt.
Also überlegt nochmal.
Hi, im Zuge meiner Klausurvorbereitung, hänge ich an einer Übungsaufgabe:
"Einem Unterprogramm sollen 2 Parameter über den Stack übergeben werden:
A: 8-Bit
B: 16-Bit
Ergänzen Sie das untenstehende Programm derart, dass der Parameter A in r16, der Parameter B in r24:r25 geladen werden"
Hier der vorgegebene code:
Kann es so einfach sein ?? Irgendwie sieht mir das nicht richtig aus. Muss ich irgendwie dem System noch sagen dass in r24 die HIGH-bytes sein sollen und die dazugehörigen LOW-bytes in r25 ?Code:.cseg lds r16, A push r16 lds r16, B+0 push r16 lds r16, B+1 push r16 rcall Unterprogramm .dseg A: .BYTE 1 B: .BYTE 2 .cseg Unterprogramm: ; Hier nun mein code den ich überlegt hatte pop r16 ;r16 von stack holen, müsste B+1 sein, also der HIGH-BYTE von B mov r24, r16 pop r16 ;nächsten stack-Inhalt holen, müsste B+0 sein, also LOW-BYTE von B mov r25, r16 pop r16 ;letzten Teil vom stack holen, müsste A sein, somit fertig ret ;return
Oder muss ich bei späterer Verwendung selber mich "erinnern" dass r24 und r25 gemeinsam eine 16-Bit-Wert darstellen ?
Sorry falls ich so blöd frage, aber alle haben doch ein gewisses Problem mit der Didaktik unseres Dozenten, so dass so (anscheinend) einfache Dinge wie der Umgang mit 16-Bit-Werten in 8-Bit-Registern nicht grad detailliert durchgenommen wurde.
Hoffe auf Hilfe hier
Gruss,
Lalas
Nein. Du vergisst, dass "rcall Unterprogramm" die Rücksprungadresse für das "ret" auf den Stack packt.
Also überlegt nochmal.
Werte auf den Stack laden, is ja klar:
Situation auf dem Stack:Code:lds r16, A push r16 lds r16, B+0 push r16 lds r16, B+1 push r16
stckp + 2 -> wert A
stckp + 1 -> wert B+0
stckp + 0 -> wert B+1
aaaaaaber:
Jetz rufst du dein Unterprogramm
RCALL Unterprogramm
und so sieht daher der Stack beim Unterprogramm aus
stckp + 4 -> wert A
stckp + 3 -> wert B+0
stckp + 2 -> wert B+1
stckp + 1 -> rücksprungadresse Hi
stckp + 0 -> rücksprungadresse Lo
Jetzt gibt's mehre Möglichkeiten:
1) Brutal und nicht schön, geht aber:
2) Besser:Code:Unterprogramm: pop r0 rücksprungadresse sichern pop r1 rücksprungadresse sichern pop R25 (B+1, siehe oben) pop R24 (B+0, siehe oben) pop R16 (A, siehe oben) ;--- irgendwas machen, R0 und R1 aber in Ruhe lassen push r1 rücksprungadresse wieder auf den Stack pop r0 r0, r1 immer symmetrisch poppen, pushen ! ret
2) AAAAAAAAber:Code:Unterprogramm: IN ZL, SPL Stackpointer nach ZL:ZH IN ZH, SPH übernehmen ; und mit "Offset" in die Zielregister laden LDD R25, Z+2 (B+1, siehe oben) LDD R24, Z+3 (B+0, siehe oben) LDD R16, Z+4 (A, siehe oben) ;--- irgendwas machen RET
Im hauptprogramm müssen jetzt noch die drein gepushten
Parameter wieder weg
Daher sieht das jetzt so aus
Is gar nicht so ohneCode:lds r16, A push r16 lds r16, B+0 push r16 lds r16, B+1 push r16 RCALL Unterprogramm pop r0 (irgendein Register) pop r0 (irgendein Register) pop r0 (hauptsache, der Stack stimmt wieder) ------- jetzt ist alles wieder paletti
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
okay, soweit verstanden, ich muss als die Rücksprung-Adresse (welche ja 16-Bit ist) zunächst vom stack holen und sichern.Zitat von PicNick
Hier kommt eine Frage auf. Alles soweit verständlich, aber wieso schiebst du r1 auf den stack zurück (push r1) und machst dann pop r0 ?? r0 muss doch auch zurück auf den stack, also push r0.Zitat von PicNick
Denkfehler von mir oder war das ein Schreibfehler ?
Aber ist das nicht gepfuschter code, wenn ich einfach die letzten 3 stack-Inhalte runterhole, nur damit der stack wieder korrekt ist ?Zitat von PicNick
Aber vielen Dank für die Erläuterungen.
Noch eine Sache zum Verständnis:
Wenn ich also einen 16-Bit Wert in z.B. r20, r21 packe, dann muss ich nicht irgendwie defnieren was davon HIGH-byte und LOW-byte ist ?? ich kopiere die einfach rein und muss bei späterer Verwendung halt selber wissen in welchem Register welcher Inhalt ist ?
Weil bei den Registern X, Y , Z ist ja die Unterteilung in L und H gegeben
war das ein Schreibfehler ?
durchaus nicht. Man könnte auch die Zahl 3 auf den Stackpointer addieren, is genauso grauslich.gepfuschter code ?
Das Problem ist, dass die Sache mit den Parametern für Unterprogramme gar nicht so ohne ist. Jede Hochsprache von C aufwärts bis Java hat da ihren eigene "CALL standards", will dir damit garnicht erst die Ohren voll-labern.
However, beim Assembler hört der gottgegebene Standard bereits mit POP u. PUSH auf, der Rest bleibt dir überlassen.
Hi- Lo: meist (bei den AVRs und anderen) isses so, dass 16-Bit gruppierungen immer aus dem geraden (low) und dem ungeraden Register (high) bestehen. R0:R1 , ..... R24:R25
Das gilt aber zwingend nur für diese 16-Bit Befehle (ADIW, LD, etc.) Es hängt also vom Befehl ab
Wenn du also LD r24, X sagen willst (muttu gucken) MUSS
xl mit low und Xh mit hi geladen sein
Bei anderen Befehlen is dem AVR das eigentlich völlig wurst. Ich würde aber raten, diese verwendung von hi-lo auch beizubehalten.
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
Tut mir leid, ich hab grad eine seeeeehhhrrr laaange LeitungZitat von PicNick
Soll dein rot werdender Smiley bedeuten das es ein Schreibfehler war ?
Wenn nicht habe ich nicht ganz verstanden wieso r1 auf den stack gepackt wird und danach wieder vom stack geholt wird in ein anderes register
ISt ein Schreibfehler
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
Lesezeichen