4 votos

Operaciones atómicas con el ensamblador en línea ampliado de C32

Estoy tratando de escribir un código atómico, en mi ejemplo de abajo necesito realizar una 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)

Según veo en los documentos, las operaciones LL y SC proporcionan una secuencia atómica de Lectura-Modificación-Escritura. ¿Cómo puedo hacer que el compilador genere código con LL, SC en lugar de LW, SW? He intentado 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 está mal, el resultado es otro que el 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 hacerlo?

1voto

Ashley Davis Puntos 3016

Pues bien, hay uno de esos momentos felices en los que sólo tengo que preguntar a alguien, y la solución me viene a la cabeza inmediatamente:

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

Es decir, necesito utilizar &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 microchips usuario andersm se sugiere utilizar Los buildins atómicos de GCC en lugar de reinventar la rueda. (Pero, estos builtins añaden dos sync instrucciones que son inútiles en PIC32, por lo que, podría tener sentido escribir mi propia macro)

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X