2016-06-20 8 views
0

Während ich mir einige Treiberimplementierungen aus dem Atmel Software Framework ansah, stieß ich auf mehrere Fälle, in denen sie eine Speicherbarriere verwendeten.Atmel-Treiber und GCC-Speicherbarriere Anwendungsfall

Barrier Definition:

#define barrier()  asm volatile("" ::: "memory") 

Beispiel 1 (Interrupt-Hilfsfunktionen):

static inline void cpu_irq_restore(irqflags_t flags) 
{ 
    barrier(); 
    SREG = flags; 
} 

Diese Barriere macht Sinn für mich. Da cpu_irq_restore implizit inlined wird, verhindert es, dass die kritische SREG-Zuweisung (von einer Ausführungsreihenfolge aus gesehen) von der tatsächlichen Funktionsaufrufposition neu geordnet wird.

Als Nebenbemerkung: SREG wird als ein Spezialfunktionsregister definiert ist definiert als:

#define _SFR_MEM8(mem_addr) (*(volatile uint8_t *)(mem_addr)) 

Beispiel 2 (von AVR TWI Treiber):

static inline status_code_t twim_release(void) 
{ 
    /* First wait for the driver event handler to indicate something 
    * other than a transfer in-progress, then test the bus interface 
    * for an Idle bus state. 
    */ 
    while (OPERATION_IN_PROGRESS == transfer.status); 

    while (! twim_idle(transfer.bus)) { barrier(); } 

    status_code_t const status = transfer.status; 

    transfer.locked = false; 

    return status; 
} 

Diese zweite Anwendungsfall jedoch ist mir nicht klar. Auf welche Weise könnte der Compiler diesen Code optimieren, so dass er ohne die bricht?

Ich glaube, ich verstehe die grundlegenden Überlegungen hinter Software-Speicherbarrieren nach dem Lesen this article.

Könnte jemand bitte die Gründe für die Verwendung der Barriere im zweiten Beispiel erklären?

Antwort

1

Die twim_idle Funktion liest wahrscheinlich den Wert eines TWI-bezogenen Spezialfunktionsregisters und prüft einige Bits darin. Ohne die Barriere besteht die Gefahr, dass der Compiler das Lesen dieses Registers optimiert und es vor die zweite Schleife verschiebt. Also dann, dass die zweite Schleife wie folgt verhalten:

bool idle = twim_idle(transfer.bus); 
while (!idle); 

Dies ist eine Optimierung, die die Schleife schneller machen würde und es wäre für liest von normalen Variablen gültig sein, aber es wäre natürlich ein Problem in diesem Fall verursachen. Das Setzen einer Barriere in die Schleife sollte verhindern, dass diese Optimierung stattfindet.

In Wirklichkeit sollten Sie diese Speicherbarriere nicht benötigen, da alle Spezialfunktionsregister mit dem Schlüsselwort qualifiziert sind, sodass der Compiler nicht versucht, Zugriffe auf sie zu cachen.

+0

Atmel Staaten in der Artikel gemocht: "Beachten Sie, dass auch eine flüchtige ASM-Anweisung relativ zu anderen Code, einschließlich über springen Anweisungen bewegt werden kann. [...] Ebenso können Sie nicht erwarten eine Folge von flüchtigen ASM Anweisungen zu bleib perfekt konsekutiv. " Unter welchen Umständen ist mir nicht ganz klar. –

+0

Ich stimme zu, dass im ersten Beispiel eine zweite Barriere nach der SREG-Zuweisung sinnvoll wäre. –

+0

Ich bin mir nicht sicher über die 'twim_idle()'. Es greift tatsächlich auf Register zu, aber der Compiler darf nicht nur die logische Reihenfolge dieser beiden while-Schleifen reorganisieren, oder? Wenn das der Fall ist, müsste man diese Art von Problem die ganze Zeit berücksichtigen. Da sie jedoch barrier() verwendet haben, ist entweder etwas an diesem Code spezifisch oder es ist einfach fehl am Platz und nicht erforderlich. –

Verwandte Themen