PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 16-Bit Parameter vom Stack holen und in 2 Register packen



lalas
09.07.2008, 15:23
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:


.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

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

sternst
09.07.2008, 15:35
Nein. Du vergisst, dass "rcall Unterprogramm" die Rücksprungadresse für das "ret" auf den Stack packt.
Also überlegt nochmal. ;-)

PicNick
09.07.2008, 16:25
Werte auf den Stack laden, is ja klar:


lds r16, A
push r16
lds r16, B+0
push r16
lds r16, B+1
push r16

Situation auf dem Stack:
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:


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) Besser:


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


2) AAAAAAAAber:
Im hauptprogramm müssen jetzt noch die drein gepushten
Parameter wieder weg
Daher sieht das jetzt so aus


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


Is gar nicht so ohne

lalas
09.07.2008, 18:58
Situation auf dem Stack:
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

okay, soweit verstanden, ich muss als die Rücksprung-Adresse (welche ja 16-Bit ist) zunächst vom stack holen und sichern.



Jetzt gibt's mehre Möglichkeiten:
1) Brutal und nicht schön, geht aber:


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


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.
Denkfehler von mir oder war das ein Schreibfehler ? ;)



2) Besser:


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


2) AAAAAAAAber:
Im hauptprogramm müssen jetzt noch die drein gepushten
Parameter wieder weg
Daher sieht das jetzt so aus


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


Aber ist das nicht gepfuschter code, wenn ich einfach die letzten 3 stack-Inhalte runterhole, nur damit der stack wieder korrekt ist ?

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

PicNick
09.07.2008, 19:25
war das ein Schreibfehler ? :oops:


gepfuschter code ?
durchaus nicht. Man könnte auch die Zahl 3 auf den Stackpointer addieren, is genauso grauslich.

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.

lalas
09.07.2008, 19:39
war das ein Schreibfehler ? :oops:

Tut mir leid, ich hab grad eine seeeeehhhrrr laaange Leitung ;)

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

PicNick
10.07.2008, 07:14
ISt ein Schreibfehler