instrucción NOP después de la bifurcación en ARMv7 Cortex M3

7

Estoy interesado, por qué para el microcontrolador Cortex M3 (stm32f103) el compilador a veces genera una instrucción NOP después de la bifurcación. Y por qué a veces no es así.

Por ejemplo:

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

Mi suposición inicial fue que la instrucción larga necesita alineación de palabras, pero BL.W después de NOP en realidad no la tiene. Si este NOP está relacionado con la tubería de alguna manera, ¿por qué hay sucursales sin nop después de ellas?

Estoy confundido.

ACTUALIZACIÓN:

Resulta que la rama puede no ser relevante en absoluto. Intenté mover la declaración de la variable local no utilizada int64_t avg, y NOP se movió junto con ella. Entonces, creo que el comentario de pjc50 es correcto y este NOP está ahí solo para permitir que el depurador ponga un punto de interrupción en esta línea.

    
pregunta Amomum

3 respuestas

1

Intente mover la línea int64_t de C hacia arriba o hacia abajo un poco. Los dos primeros son claramente parte de un bucle for; pero la línea 66 no ha generado ningún código en absoluto. Supongo que el NOP es para el beneficio del depurador, de modo que cada línea de C genere al menos una instrucción.

(No todos los depuradores hacen esto en todas las plataformas; Visual Studio simplemente moverá su punto de interrupción a la línea más cercana que tenga un código asociado).

    
respondido por el pjc50
4

Los compiladores de lotes (¿la mayoría? ¿todos?) terminan poniendo instrucciones NOP después de algunas (pero no otras) instrucciones tipo salto / rama.

Cuando el compilador ve una instrucción de tipo "salto", tiene dos instrucciones diferentes que pueden hacer el trabajo. Uno es relativo, uno es absoluto.

Uno es un salto relativo, y uno es un salto absoluto. El salto relativo es más rápido y especifica un salto en relación con la instrucción actual: la dirección a la que se saltará es de un solo byte, por lo que puede saltar 128 bytes hacia adelante, o 127 bytes hacia atrás.

El otro es un salto absoluto, es más lento y especifica la dirección a la que se debe saltar. Esto puede saltar a cualquier parte.

El problema es que, al saltar hacia adelante, es posible que la dirección de destino aún no se conozca. Tendría que compilar el código hasta el destino de salto y luego calcular si tiene menos de 128 bytes. Por supuesto, para calcular cuántos bytes para saltar, necesita saber cuántos bytes ocupa esta instrucción, así como todas las instrucciones entre aquí y allá.

Esto se encuentra fuera de la categoría de pago de un compilador; deja espacio para un salto absoluto, luego, en la segunda pasada, cuando sabe dónde están todas las direcciones, llena los huecos, ya sea poniendo un salto relativo más eficiente (+ un NOP, porque tiene que ocupar el mismo número de saltos). bytes!), o poniendo en un salto absoluto.

    
respondido por el AMADANON Inc.
0

Los microcontroladores Cortex-M3 están construidos con una arquitectura de 32 bits, pero no limitan las entradas a este tamaño de bus (consulte enlace ). La arquitectura tiene un pequeño búfer de captación previa para manejar el caso de las instrucciones de palabra no alineadas, de modo que cuando se toma la rama no hay problema. Cuando no se toma la rama, deberá limpiar la tubería para eliminar la elección errónea y volver a buscar. No puede obtener directamente desde 0x080004B2, ya que no está alineado con 4 bytes y si se recuperara de 0x080004B0, volvería a leer la rama. El NOP es esencial para el relleno adicional que necesita obtener de la palabra alineada 0x080004B4 y continuar desde allí.

enlace

    
respondido por el carlab

Lea otras preguntas en las etiquetas