RISC-V, Funktionen?
-
Hi, weiß jemand, was hier falsch sein könnte?
.text li a0, 0 li a1, 1 li a2, 2 li a3, 21 loop1: beq a0, a3, end0 addi a1, a0, 0 jal func1 # 7, 14, 21, ... j loop1 # a0=a1+a2+5 func1: addi sp, sp, -8 sw s1, 4(sp) sw s0, 0(sp) li a3, 5 add a0, a1, a2 add a0, a0, a3 lw s0, 0(sp) lw s1, 4(sp) addi sp, sp, 8 jr ra end0:
func1
soll 0, 7, 14, 21, usw. berechnen. Das Problem ist, infunc1
wird ina3
5 geladen und damit wird der vorherige Wert vona3
(21) überschrieben und die Schleife (loop1
) hält nicht an.
-
@EinNutzer0 sagte in RISC-V, Funktionen?:
Hi, weiß jemand, was hier falsch sein könnte?
Vermutlich das hier:
Das Problem ist, in
func1
wird ina3
5 geladen und damit wird der vorherige Wert vona3
(21) überschrieben und die Schleife (loop1
) hält nicht an.Keine Ahnung von RISC-V-Assembler, aber du solltest das Register irgendwo sichern und wiederherstellen, damit der aufrufende Code weiterhin den korrekten Wert in
a3
hat. Wenn ich mir das hier ansehe, dann ist es wohl so als seia3
gemäss konventioneller Aufrufkonvention Caller-Saved, es ist also Aufgabe den aufrufenden Codes das Register wieder in den Zustand zu versetzen, den es bei Funktionaufruf hatte.Das geht entweder, indem du den Wert auf dem Stack zwischenspeicherst oder - wo der RISC-V doch so viele Register hat - in einem anderen Register. Z.B. in einem Callee-Saved-Register. Ein solches muss die aufgerufene Funktion sichern und wiederherstellen und das wird für
s0
unds1
ja auch bereits in Zeilen 16+17/23+24 gemacht, wenn ich mit meinem bescheidenen Verständnis den Code richtig interpretiere (wenn auch unnötig IMHO, da diese Register von der Funktion augenscheinlich nicht verändert werden). Nimm doch z.B.s1
um dir im aufrufenden Code den Wert vona3
zu merken. Oder verwende gleichs1
statta3
im aufrufenden Code.
-
@Finnegan Jap, daran lag es... Hier noch mal komplett:
.text li a0, 0 li a1, 1 li a2, 2 li a3, 21 # loop1 wird genau 3mal durchlaufen. loop1: beq a0, a3, end0 addi a1, a0, 0 jal func1 j loop1 # a0=a1+a2+5 func1: addi sp, sp, -8 sw s1, 4(sp) sw s0, 0(sp) # Wir können s0 und s1 als interne Variablen verwenden (callee). # a0, a1 und a2 sind Parameter- und Rückgaberegister (caller und callee). # a0 bekommt das Ergebnis. # a1 und a2 werden innerhalb der Funktion nicht geändert. li s0, 5 add a0, a1, a2 add a0, a0, s0 lw s0, 0(sp) lw s1, 4(sp) addi sp, sp, 8 jr ra end0:
Danke, das Thema kann schon als gelöst angesehen werden.
-
@EinNutzer0 sagte in RISC-V, Funktionen?:
Danke, das Thema kann schon als gelöst angesehen werden.
Ist das ne Übungsaufgabe oder wird daraus eigener Code, der irgendwo laufen soll? Mir gefallen ja irgendwie die Speicherzugriffe innerhalb von
func1
nicht, wo man doch so viele Register zur Verfügung hat*. Bevor man sowas per Hand schreibt, sollte man das besser nen optimierenden Compiler machen lassen... für ne Übungsaufgabe ist wär aber durchaus okay.* ja, x86-Geschädigter hier
-
@Finnegan sagte in RISC-V, Funktionen?:
Ist das ne Übungsaufgabe oder wird daraus eigener Code
Beides. Aber keine Angst, ein Flugzeug wollte ich nicht programmieren.
Aber ja,
addi a0, a0, 5
ginge genauso. (Ohnes0
...) Aber das ist vornehmlich eine Übung für mich.