NOP-Anweisung nach Verzweigung auf ARMv7 Cortex M3

7

Ich bin interessiert, warum für Cortex M3 Mikrocontroller (stm32f103) Compiler manchmal einen NOP-Befehl nach der Verzweigung generiert. Und warum manchmal nicht.

Zum Beispiel:

0x08000496 2400      MOVS     r4,#0x00
0x08000498 4625      MOV      r5,r4
0x0800049A E006      B        0x080004AA
    64: res=res+a[i];
    65: }
0x0800049C F85A0034  LDR      r0,[r10,r4,LSL #3] // No NOP after B
0x080004A0 EB100808  ADDS     r8,r0,r8
0x080004A4 1C64      ADDS     r4,r4,#1
0x080004A6 F1450500  ADC      r5,r5,#0x00
0x080004AA 1BA0      SUBS     r0,r4,r6
0x080004AC EB750007  SBCS     r0,r5,r7
0x080004B0 DBF4      BLT      0x0800049C
    66: int64_t avg=res/x;
0x080004B2 BF00      NOP      // <------------------- NOP after BLT
    69: int v=countbits1(5);
0x080004B4 2005      MOVS     r0,#0x05
0x080004B6 F7FFFFA2  BL.W     countbits1 (0x080003FE)
0x080004BA 9001      STR      r0,[sp,#0x04]     // No NOP after BL.W
    72: unsigned int b=countLeadingZeros(5);
    73:  
0x080004BC 2005      MOVS     r0,#0x05

Meine anfängliche Vermutung war, dass lange Anweisungen eine Wortausrichtung erfordern, aber BL.W nach NOP hat sie tatsächlich nicht. Wenn dieser NOP irgendwie mit der Pipeline zusammenhängt, warum gibt es dann Zweige ohne NOPs?

Ich bin verwirrt.

AKTUALISIEREN:

Es stellt sich heraus, dass der Zweig möglicherweise überhaupt nicht relevant ist. Ich habe versucht, die Deklaration der nicht verwendeten lokalen Variablen int64_t avg zu verschieben - und NOP hat sie mit verschoben. Ich glaube also, dass der pjc50-Kommentar richtig ist und dieser NOP nur dazu da ist, dass der Debugger einen Haltepunkt in diese Zeile setzt.

Amomum
quelle
3
Versuchen Sie, die int64_t-Zeile von C etwas nach oben oder unten zu verschieben. Die ersten beiden sind eindeutig Teil einer for-Schleife. Zeile 66 hat jedoch überhaupt keinen Code generiert. Ich vermute, dass der NOP dem Debugger zugute kommt, sodass jede Zeile von C mindestens einen Befehl generiert.
pjc50
@ pjc50 das ist jetzt interessant! Dieser NOP ist tatsächlich mit int64_t avg verbunden; Die bewegliche Linie 66 bewegte den NOP. Wenn ich jedoch den Durchschnittstyp in int32_t ändere, gibt es kein NOP. Diese lokale Variable wird tatsächlich nicht verwendet, sodass der Compiler überhaupt keinen Code dafür generiert. Abgesehen von diesem NOP für den 64-Bit-Typ. Wenn ich den Typ ändere, kann ich immer noch einen Haltepunkt in diese Zeile setzen (und er wird in den MOVS sein). Sehr interessant.
Amomum
Irgendwelche Ideen, warum 64-Bit-Variablen mit einem NOP ausgezeichnet werden?
Amomum
ARM und LinkedIn haben beide großartige Foren für diese Art von Fragen - Sie können es dort versuchen. Ich muss ein paar Kommentare hinzufügen: Manchmal werden beide Ergebnisse eines Zweigs abgerufen, und je nach Ergebnis des Zweigs wird eine Alternative mit NOP herausgeholt. Der Cortex M3 kann sich auch dafür entscheiden, keine NOPs auszuführen. Dies ist ein interessanter Punkt, wenn Sie sie für kurze Verzögerungen verwenden. Ich hoffe, diese Kommentare sind relevant.
Ameise
Da dies meistens eine Compiler-Frage ist, die wenig mit EE zu tun hat ... haben Sie vielleicht mehr Glück, wenn Sie sie auf SO stellen.
Fizz

Antworten:

1

Versuchen Sie, die int64_t-Zeile von C etwas nach oben oder unten zu verschieben. Die ersten beiden sind eindeutig Teil einer for-Schleife. Zeile 66 hat jedoch überhaupt keinen Code generiert. Ich vermute, dass der NOP dem Debugger zugute kommt, sodass jede Zeile von C mindestens einen Befehl generiert.

(Nicht alle Debugger tun dies auf allen Plattformen. Visual Studio verschiebt Ihren Haltepunkt einfach in die nächste Zeile, der Code zugeordnet ist.)

pjc50
quelle
Sie haben Recht, durch Verschieben der Deklaration der Variablen wurde die NOP-Anweisung verschoben. Verzweigungsanweisungen erwiesen sich als irrelevant.
Amomum
4

Viele (die meisten? Alle?) Compiler setzen am Ende NOP-Anweisungen nach einigen (aber nicht anderen) Anweisungen vom Typ Sprung / Verzweigung.

Wenn der Compiler eine Anweisung vom Typ "Sprung" sieht, verfügt er über zwei verschiedene Anweisungen, die die Aufgabe ausführen können. Einer ist relativ, einer ist absolut.

Einer ist ein relativer Sprung und einer ist ein absoluter Sprung. Der relative Sprung ist schneller und gibt einen Sprung relativ zum aktuellen Befehl an. Die Adresse, zu der gesprungen werden soll, ist ein einzelnes Byte, sodass 128 Bytes vorwärts oder 127 Bytes rückwärts gesprungen werden können.

Der andere ist ein absoluter Sprung - dieser ist langsamer und gibt die Adresse an, zu der gesprungen werden soll. Dies kann überall hin springen.

Das Problem ist, dass beim Vorwärtsspringen die Zieladresse möglicherweise noch nicht bekannt ist. Sie müsste den Code bis zum Sprungziel kompilieren und dann herausfinden, ob er weniger als 128 Byte beträgt. Um herauszufinden, wie viele Bytes vorwärts springen sollen, müssen Sie natürlich wissen, wie viele Bytes DIESER Befehl beansprucht, sowie jeden Befehl zwischen hier und da.

Dies liegt weit außerhalb der Gehaltsstufe eines Compilers. es lässt Platz für einen absoluten Sprung, dann füllt es beim zweiten Durchgang, wenn es weiß, wo sich alle Adressen befinden, die Lücken - entweder durch einen effizienteren relativen Sprung (+ ein NOP, weil es die gleiche Anzahl von aufnehmen muss) Bytes!) oder einen absoluten Sprung machen.

AMADANON Inc.
quelle
0

Cortex-M3-Mikrocontroller sind mit einer 32-Bit-Architektur ausgestattet, beschränken die Eingaben jedoch nicht auf diese Busgröße (siehe http://www.silabs.com/Support%20Documents/TechnicalDocs/EFM32-Cortex-M3-RM.pdf ). . Die Architektur verfügt über einen kleinen Prefetch-Puffer, um den Fall der nicht ausgerichteten Wortbefehle zu behandeln. Wenn also die Verzweigung ausgeführt wird, haben Sie kein Problem. Wenn der Zweig nicht genommen wird, muss die Pipeline gespült werden, um die falsche Auswahl zu entfernen und erneut abzurufen. Es kann nicht direkt von 0x080004B2 abgerufen werden, da dies nicht 4-Byte-ausgerichtet ist. Wenn es von 0x080004B0 abgerufen wird, wird der Zweig erneut gelesen. Das NOP ist dann für die zusätzliche Auffüllung erforderlich, die erforderlich ist, um aus dem Wort 0x080004B4 abzurufen und von dort aus fortzufahren.

http://community.arm.com/groups/embedded/blog/2014/11/07/intern-inquiry-1031--assembly-on-cortex-m3-question

Carlab
quelle
Ich fürchte, das ist nicht der Fall. Bitte aktualisieren Sie die Frage.
Amomum