Forum: Mikrocontroller und Digitale Elektronik Semaphore für STM32 in Assembler


von Peter (Gast)


Lesenswert?

Hallo,

ich habe zwei Funktionen zur Implementierung einer Semaphore in 
Assembler:

x_semaphore.s:
1
  .syntax unified
2
  .cpu cortex-m3
3
  .fpu softvfp
4
  .thumb
5
6
  .global x_semaphore_dec
7
  .global x_semaphore_inc
8
9
  .section .text.x_semaphore_dec
10
x_semaphore_dec:
11
1:  LDREX   r1, [r0]
12
    CMP    r1, #0        /* Test if semaphore holds the value 0 */
13
    BEQ     2           /* If it does, block before retrying */
14
    SUB     r1, #1        /* If not, decrement temporary copy */
15
    STREX   r2, r1, [r0]  /* Attempt Store-Exclusive */
16
    CMP     r2, #0        /* Check if Store-Exclusive succeeded */
17
    BNE     1            /* If Store-Exclusive failed, retry from start */
18
    DMB                   /* Required before accessing protected resource */
19
    BX      lr
20
21
2:  /* Wait for signal to retry */
22
  @ SIGNAL_UPDATE
23
    B       1
24
25
26
  .section .text.x_semaphore_inc
27
x_semaphore_inc:
28
1:  LDREX   r1, [r0]
29
    ADD     r1, #1          /* Increment temporary copy */
30
    STREX   r2, r1, [r0]    /* Attempt Store-Exclusive */
31
    CMP     r2, #0          /* Check if Store-Exclusive succeeded */
32
    BNE     1             /* Store failed - retry immediately */
33
    CMP     r0, #1        /* Store successful - test if incremented from 
34
                 zero */
35
    DMB                     /* Required before releasing protected resource */
36
    BGE     2           /* If initial value was 0, signal update */
37
    BX      lr
38
39
2:  /* Signal waiting processors or processes */
40
  @ SIGNAL_UPDATE
41
    BX      lr

Das Ganze stammt von hier:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html

Da sich die Funktion x_semaphore aufhängt bei dem folgenden Aufruf, 
stellen sich mir ein paar Fragen:
1
  uint32_t semaphore = 0;
2
3
  x_semaphore_inc(&semaphore);
4
5
  test_assert(1 == semaphore, "test_semaphore_inc");

Was bedeutet eigentlich @ SIGNAL_UPDATE ?

Dieses Macro ist hier definiert und beinhaltet offenbar ... nix!
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/CJAHGJEF.html

Warum hängt sich meine Kiste auf? - Ein Fehler in den 
Assembler-Routinen?

Ich hoffe, das ist alles so verständlich erklärt, und es kann mir jemand 
helfen.

Danke und Gruß Peter

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Peter schrieb:
> CMP     r0, #1        /* Store successful - test if incremented from
>                  zero */

Muss hier nicht r1 stehen? r0 ist doch der Pointer...


Peter schrieb:
> Da sich die Funktion x_semaphore aufhängt
Definiere "aufhängen"...

Peter schrieb:
> Was bedeutet eigentlich @ SIGNAL_UPDATE ?

Das ist wohl zur Synchronisation mehrerer Prozessoren (gibts nicht beim 
STM32) und Threads gedacht.

Soll das ein Spinlock werden oder ein blockierender Semaphore via 
Scheduler?
Im zweiten Fall musst du in der x_semaphore_dec bei SIGNAL_UPDATE den 
Scheduler bitten den Thread blockieren zu lassen. In der x_semaphore_inc 
musst du dem Scheduler mitteilen, andere wartende Threads aufzuwecken.

Aber deine Logik ist falsch, muss es nicht sein:
1
    CMP     r1, #1        /* Store successful - test if incremented from 
2
                 zero */
3
    DMB                     /* Required before releasing protected resource */
4
    BHI     2           /* If initial value was 0, signal update */
5
    SIGNAL_UPDATE  /* Signal waiting processors or processes */
6
2:  
7
    BX      lr
Wenn der Semaphor-Wert nach dem Inkrementieren echt-größer 1 ist, ("BHI" 
für unsigned, "GE" ist signed), war er also vorher echt-größer 0, somit 
kann es keinen wartenden Prozess geben und man muss niemanden aufwecken. 
Ansonsten braucht es halt SIGNAL_UPDATE.

von Peter (Gast)


Lesenswert?

Hallo Niklas,

danke für die Denkanstöße.

Niklas G. schrieb:
> Definiere "aufhängen"...

Die test_assert() Funktion wird nicht mehr aufgerufen.

Niklas G. schrieb:
> Soll das ein Spinlock werden oder ein blockierender Semaphore via
> Scheduler?

Ein Spinlock (Mutex?) - auch wenn semaphore dran steht. Ich muss das 
noch ändern.

Folgendes funktioniert:
1
  .section .text.x_semaphore_inc
2
x_semaphore_inc:
3
1:  LDREX   r1, [r0]
4
    ADD     r1, #1          /* Increment temporary copy */
5
    STREX   r2, r1, [r0]    /* Attempt Store-Exclusive */
6
    CMP     r2, #0          /* Check if Store-Exclusive succeeded */
7
    BNE     1             /* Store failed - retry immediately */
8
    CMP     r0, #1        /* Store successful - test if incremented from 
9
                 zero */
10
    DMB                     /* Required before releasing protected resource */
11
//    BGE     2           /* If initial value wasn't 0, signal update */
12
    BX      lr
13
14
2:  /* Signal waiting processors or processes */
15
  @ SIGNAL_UPDATE
16
  BX      lr

Wenn ich
1
    BGE    2

wieder einfüge, dann hängt sich die Kiste auf.


Mal abgesehen davon, dass ich mir das in meinem Fall sparen kann, wüsste 
ich doch gerne, was da schief läuft?

Gruß Peter

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Peter schrieb:
> Folgendes funktioniert:

Du hast ja immer noch r0 statt r1 drin.

Peter schrieb:
> wüsste
> ich doch gerne, was da schief läuft?

Dann steppe doch mal im Debugger jede Anweisung einzeln durch und schau 
wie die Endlosschleife zustande kommt.

Peter schrieb:
> Wenn ich    BGE    2
>
> wieder einfüge, dann hängt sich die Kiste auf.

Welchen Assembler nutzt du überhaupt? Beim GNU Assembler musst du "bge 
2f" (forwards) schreiben. Sonst springt er an Adresse 2, und nicht an 
das nächste Label 2! Das Gleiche gilt für das "bne", hier muss es "bne 
1b" (backwards) heißen.

von Peter (Gast)


Lesenswert?

Niklas G. schrieb:
> Du hast ja immer noch r0 statt r1 drin.

Das stimmt schon so:

LDREX   r1, [r0]     -> Lade Addresse nach r1
ADD     r1, #1       -> Erhöhe den Wert in r1 um 1
STREX   r2, r1, [r0] -> Schreibe r1 in einem Ruck zurück nach r0
CMP     r2, #0       -> Hat das so funktioniert mit dem Rückschreiben?
BNE     1            -> Nein, da in r2 eine 0 steht - also nochmal.
CMP     r0, #1       -> War vorher der Wert 0?

usw. ...

Niklas G. schrieb:
> Welchen Assembler nutzt du überhaupt?

Den von ARM. Das mit den Sprüngen stimmt.

Gruß Peter

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Peter schrieb:
> Das stimmt schon so:

Peter schrieb:
> CMP     r0, #1       -> War vorher der Wert 0?

In r0 steht die Adresse der Semaphor. Also Vermutlich 0x2001... . Das 
ist immer größer 1. Also kannst du das "CMP" weglassen und statt "BGE" 
einfach "B" schreiben.

Peter schrieb:
> Das mit den Sprüngen stimmt.
Wenn ich
http://www.keil.com/support/man/docs/armasm/armasm_dom1359731175956.htm
richtig verstehe muss es hier "B %1" heißen.
Zeig mal die Disassembly.

von Peter (Gast)


Lesenswert?

Niklas G. schrieb:
> In r0 steht die Adresse der Semaphor. Also Vermutlich 0x2001... . Das
> ist immer größer 1. Also kannst du das "CMP" weglassen und statt "BGE"
> einfach "B" schreiben.

Du hast recht. Ich habs geändert.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.