Operaciones atómicas utilizando un ensamblador en línea extendido de C32

4

Estoy intentando escribir código atómico, en mi ejemplo a continuación, necesito realizar la operación simple a ^= 1;

    static volatile int a = 0;

   //-- a ^= 1;
   __asm__ __volatile__( "xori    %0,     %0,     1"
         : "=r"(a)
         : "r"(a)
         );

El código generado no es atómico:

9D0014E8  8F828018   LW V0, -32744(GP)
9D0014EC  38420001   XORI V0, V0, 1
9D0014F0  AF828018   SW V0, -32744(GP)

Como veo en los documentos, las operaciones LL y SC proporcionan una secuencia atómica de lectura-modificación-escritura. ¿Cómo puedo hacer un compilador para generar código con LL, SC en lugar de LW, SW? Intenté escribir ese código yo mismo:

  static volatile int a = 0;

  __asm__ __volatile__( "ll      $t1,     0(%0)": : "r"(a) );
  __asm__ __volatile__( "xori    $t1,     $t1,     1" );
  __asm__ __volatile__( "sc      $t1,     0(%0)": : "r"(a) );

Pero esto es incorrecto, el resultado es distinto de lo que necesito:

140:                       __asm__ __volatile__( "ll      $t1,     0(%0)": : "r"(a) );
9D001454  8F828018   LW V0, -32744(GP)    # WRONG! | I need for LL T1, -32744(GP) instead of
9D001458  C0490000   LL T1, 0(V0)         # WRONG! | these two LW, LL instructions
141:                       __asm__ __volatile__( "xori    $t1,     $t1,     1" );
9D00145C  39290001   XORI T1, T1, 1
142:                       __asm__ __volatile__( "sc      $t1,     0(%0)": : "r"(a) );
9D001460  8F828018   LW V0, -32744(GP)    # WRONG! | I need for SC T1, -32744(GP) instead of
9D001464  E0490000   SC T1, 0(V0)         # WRONG! | these two LW, SC instructions

¿Cómo puedo hacer eso?

    
pregunta Dmitry Frank

1 respuesta

3

Bueno, hay uno de estos momentos felices cuando necesito preguntarle a alguien, y la solución viene a mi mente de inmediato:

   __asm__ __volatile__( "ll      $t1,     0(%0)": : "r"(&a) );
   __asm__ __volatile__( "xori    $t1,     $t1,     1" );
   __asm__ __volatile__( "sc      $t1,     0(%0)": : "r"(&a) );

I.e. Necesito usar &a en lugar de a . Ahora, el código generado es:

104:                    __asm__ __volatile__( "ll      $t1,     0(%0)": : "r"(&a) );
9D001434  27828018   ADDIU V0, GP, -32744
9D001438  C0490000   LL T1, 0(V0)
105:                    __asm__ __volatile__( "xori    $t1,     $t1,     1" );
9D00143C  39290001   XORI T1, T1, 1
106:                    __asm__ __volatile__( "sc      $t1,     0(%0)": : "r"(&a) );
9D001440  E0490000   SC T1, 0(V0)

Que parece ser lo que necesito. Nota: para hacerlo mejor, necesitamos usar la instrucción "beqz" para hacer un bucle si SC falló (hay un ejemplo en Referencia rápida de instrucciones MIPS32 ). Pero esta es otra historia.

Más, en foro de microchip el usuario andersm sugiere utilizar componentes atómicos de GCC en lugar de reinventar la rueda. (Pero, estas incorporaciones agregan dos instrucciones sync que son inútiles en PIC32, por lo tanto, podría tener sentido escribir mi propia macro)

    
respondido por el Dmitry Frank

Lea otras preguntas en las etiquetas