STM32: Division durch Null

OP #6098945
Lesenswert?

Guten Morgen,

ich stehe gerade vor einem Rätsel. Ich wollte nur die Fehler-Ausgabe 
testen. Als praktischste Stelle kam mir ein Bresenham-Algorithmus vor, 
weil der häufig aufgerufen wurde.
1
    typedef struct State32_s
2
    {
3
        int32_t z;  /**< Zaehler */
4
        int32_t n;  /**< Nenner */
5
        int32_t r;  /**< Rest */
6
    }
7
    State32_t;
8

9
    State32_t GState = {.z = 300, .r = 0};
10

11
    static int32_t foo(void)
12
    {
13
        State32_t *State = &GState;
14
        
15
        int32_t dy = ((int64_t) State->z * dx + State->r)/State->n;
16
        State->r = ((int64_t) State->z * dx + State->r)%State->n;
17

18
        return dy;
19
    }

Mit dem Debugger habe ich State->n auf Null gesetzt. Von mir wurden auch 
keine extra Fehler-Handler als der HardFault_Handler() implementiert. 
Trotzdem wird diese Funktion mit State->n == 0 mehrmals durchlaufen, 
ohne dass ein Fehler auftritt. Der Rückgabewert wird auch weiter 
verwendet.

Was passiert hier?
Kann man in __eabi_ldivmod() irgendwie hineingucken?
Gast #6098977
Lesenswert?

Walter T. schrieb:

> Mit dem Debugger habe ich State->n auf Null gesetzt. Von mir wurden auch
> keine extra Fehler-Handler als der HardFault_Handler() implementiert.
> Trotzdem wird diese Funktion mit State->n == 0 mehrmals durchlaufen,
> ohne dass ein Fehler auftritt. Der Rückgabewert wird auch weiter
> verwendet.
>
> Was passiert hier?

https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
Da steht: "To enable hardware reporting of div0 errors we need to 
configure the CCR"
#6099004
Lesenswert?

Unabhängig von der fehlenden Error-Meldung:
Kann das der type-cast von 64Bit auf 32Bit sein ?
angenommen mit geteilt durch Null geht der 64Bit Wert auf den maximal 
positiven Wert
0X7FFF FFFF FFFF FFFF
wenn der cast daraus ein
0XFFFF FFFF
macht, käme -1 dabei heraus.
OP #6099041
Lesenswert?

Das ließ sich ja einfach testen:
1
typedef struct State32_s
2
{
3
    int32_t z;  /**< Zaehler */
4
    int32_t n;  /**< Nenner */
5
    int32_t r;  /**< Rest */
6
}
7
State32_t;
8

9
State32_t GState = {.z = 300, .r = 0, .n = 0};
10

11

12
volatile int64_t temp = 0;
13

14
static int32_t foo(int32_t dx)
15
{
16
    State32_t *State = &GState;
17

18
    temp = ((int64_t) State->z * dx + State->r)/State->n;
19
    int32_t dy = temp;
20
    State->r = ((int64_t) State->z * dx + State->r)%State->n;
21

22
    return dy;
23
}
24

25

26
/* Funktion zum Testen von Sachen. */
27
exit_t runToShow(void)
28
{
29
    int32_t dx = 20000;
30
    volatile int32_t dy;
31

32
    dy = foo(dx);
33
    printf("dy = %i", dy);
34

35
    return EXIT_SUCCESS;
36
}

Ergebnis 1: Ja, Du hast Recht. Auf dem STM32 ist das tatsächlich ein von 
__eabi_ldivmod() bestmöglich behandelter Overflow.
temp = 0x7fffffffffffffff.

Ergebnis 2: Unter Windows (wo wahrscheinlich direkt die CPU den 
Divisionsbefehl bekommt) stürzt das wie erwartet gnadenlos ab.
(Firma: fritzler-avr.de) #6099785
Lesenswert?

Aus dem ARM Infocenter:
Integer division is implemented by calling the C library functions 
__aeabi_idiv and __aeabi_uidiv. These check for divison by zero. If 
integer division by zero is detected, a branch to __aeabi_idiv0 is made. 
So to trap the division by zero, all you need to do is place a 
breakpoint on __aeabi_idiv0.

Also für die 64Bit Version das Symbol im Linkerscript ersetzen und dann 
einen Hardfault selber aufrufen?

Ein 64Bit div kann der 32Bit ARM Kern ja nicht selber ausführen.
Aber wieso bläst du da auf 64Bit auf?
Der Bresenham ist ja zum Linien zeichnen auf Rastern für eine GUI oder?
Das wird dann ja recht langsam in Software.

Ansonsten hat ein gast schon geschrieben, dass auch das 32Bit HW Div0 
Trap erst aktiviert werden muss.
Weiteres hier dazu: Beitrag "ARM Cortex-M3/4/7 Faulthandler"
OP #6099807
Lesenswert?

Mw E. schrieb:
> So to trap the division by zero, all you need to do is place a
> breakpoint on __aeabi_idiv0.

Danke für den interessanten Aspekt.

Meine naive Frage: Wie setzt man denn einen Breakpoint in eine 
Library-Funktion mit einem grafischen Debugger? Mein erster Ansatz: 
Map-File aufrufen, nach der Funktion suchen und an die Adresse springen. 
(Erst einmal: Super, das das geht. Ein für mich neues und praktisches 
Hilfsmittel.) Geht es noch einfacher?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren