RISC-V, Funktionen?


  • Gesperrt

    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, in func1 wird in a3 5 geladen und damit wird der vorherige Wert von a3 (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 in a3 5 geladen und damit wird der vorherige Wert von a3 (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 sei a3 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 und s1 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 von a3 zu merken. Oder verwende gleich s1 statt a3 im aufrufenden Code.


  • Gesperrt

    @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 😉


  • Gesperrt

    @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. (Ohne s0...) Aber das ist vornehmlich eine Übung für mich.


Anmelden zum Antworten