Gleitkommaoperationen

Aus C und Assembler mit Raspberry
Version vom 7. April 2025, 11:58 Uhr von Satyria (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „In diesem Kapitel werden wir uns mit Gleitkommaoperationen im ARM64-Assembler beschäftigen. Die Schwerpunkte liegen auf den FPU-Registern (Floating Point Unit), einem Überblick über die Register und deren Verwendung in Funktionen. Ebenso werden wichtige Hinweise zur Verwendung der Register für Gleitkommaoperationen gegeben. == FPU-Register: Überblick == Unter ARM64 haben wir eine dedizierte Einheit für Gleitkommaoperationen, die sogenannte FPU (Fl…“)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

In diesem Kapitel werden wir uns mit Gleitkommaoperationen im ARM64-Assembler beschäftigen. Die Schwerpunkte liegen auf den FPU-Registern (Floating Point Unit), einem Überblick über die Register und deren Verwendung in Funktionen. Ebenso werden wichtige Hinweise zur Verwendung der Register für Gleitkommaoperationen gegeben.

FPU-Register: Überblick

Unter ARM64 haben wir eine dedizierte Einheit für Gleitkommaoperationen, die sogenannte FPU (Floating Point Unit). Diese Einheit verwendet spezifische Register, um Gleitkommaoperationen auszuführen.

Registerüberblick

  • s0 - s31: Einzelpräzisions-Gleitkomma-Register (32-Bit)
  • d0 - d31: Doppelpräzisions-Gleitkomma-Register (64-Bit)
  • q0 - q31: Vektorregister (128-Bit)

Diese Register werden für verschiedene Arten von Gleitkommaoperationen und SIMD (Single Instruction, Multiple Data) verwendet. Hier konzentrieren wir uns hauptsächlich auf die Register d0 bis d31 für Doppelpräzisions-Gleitkommaoperationen.

Verwendung der FPU-Register in Funktionen

Um Gleitkommaoperationen in ARM64-Assembler durchzuführen, sind bestimmte Anweisungen und Register zu beachten. Im Folgenden finden Sie grundlegende Beispiele und Best Practices für die Durchführung von Gleitkommaoperationen.

Beispiel: Gleitkommaaddition

.section .data
    var1: .double 3.14
    var2: .double 1.618

.section .text
.global _start

_start:
    // Lade Gleitkommawerte in d-Register
    ldr x0, =var1
    ldr d0, [x0]
    ldr x1, =var2
    ldr d1, [x1]

    // Führe die Gleitkommaaddition durch
    fadd d2, d0, d1  // d2 = d0 + d1

    // Beispiel: Rückgabe des Ergebnisses mit einem Systemaufruf 
    // (zur Vereinfachung hier nicht gezeigt, da Gleitkomma nicht direkt unterstützt wird)

    // Exit system call
    mov x8, #93       // syscall number for exit
    mov x0, #0        // exit code
    svc 0

Hinweise zur Verwendung von FPU-Registern

  • Laden und Speichern von Gleitkommawerten: Verwendung von Load/Store-Instruktionen wie ldr und str, um Werte in und aus den FPU-Registern zu laden bzw. zu speichern.
  • Arithmetische Operationen: Verwendung von speziellen Instruktionen wie fadd (Addition), fsub (Subtraktion), fmul (Multiplikation) und fdiv (Division) für Gleitkommaarithmetik.
  • Beachtung von Doppelpräzisionsregistern: Verwenden Sie d-Register für doppelpräzise Gleitkommazahlen.
  • Parameterübergabe: Gleitkommaargumente werden in den d0 bis d7 Registern übergeben, ähnlich wie Ganzzahlen in x0 bis x7.

Beispiel: Gleitkommamultiplikation in einer Funktion

Funktionsdefinition in C:

// float_functions.c
double multiply(double a, double b) {
    return a * b;
}

Aufruf der Funktion aus Assembler:

.extern multiply

.global _start

_start:
    // Parameter für die Funktion laden
    ldr x0, =var1
    ldr d0, [x0]
    ldr x1, =var2
    ldr d1, [x1]

    // Aufruf der C-Funktion
    bl multiply

    // Das Ergebnis ist in d0
    // Beispiel: Gleitkommaergebnis weiter verarbeiten
    // (hier nicht weiter verwendet)

    // Exit system call
    mov x8, #93
    mov x0, #0
    svc 0

Funktionsdefinition im Assembler:

.global multiply

multiply:
    fmul d0, d0, d1   // Führe die Multiplikation durch: d0 = d0 * d1
    ret               // Rückkehr zur aufrufenden Funktion

Parameterübergabe und Rückgabewert

Wie bereits erwähnt, werden Gleitkommaargumente in den Registern d0 bis d7 übergeben und Rückgabewerte in d0. Hier ein Beispiel, das zeigt, wie Sie eine Gleitkommafuntionsdefinition in Assembler schreiben und von C aus aufrufen.

C-Beispiel:

// main.c
#include <stdio.h>

extern double asm_multiply(double a, double b);

int main() {
    double result = asm_multiply(3.14, 1.618);
    printf("Ergebnis: %f\n", result);
    return 0;
}

Assemblerfunktion:

.global asm_multiply

asm_multiply:
    fmul d0, d0, d1   // Führe die Multiplikation durch: d0 = d0 * d1
    ret               // Rückkehr zur aufrufenden Funktion

Kompilierung und Linken:

gcc -c main.c
as -o float_functions.o float_functions.s
gcc -o myprogram main.o float_functions.o

Durch die Beachtung dieser Prinzipien können Sie Gleitkommaoperationen in ARM64-Assembler effektiv nutzen und mit C-Funktionen integrieren.