Microchip XC8: asignación de múltiples bytes con endian inverso

1

La mayoría de los chips dirigidos por XC8, si no todos, procesan un byte a la vez. Para asignar un valor de una variable de múltiples bytes a otra, tiene que cargar los primeros 8 bits de la fuente en WREG y almacenarlos en los primeros 8 bits del destino y luego hacerlo de nuevo con los siguientes 8 bits. En el nivel de ensamblaje, esto hace que sea trivial ajustar el endianness al mismo tiempo simplemente reordenando las instrucciones de carga o las instrucciones de la tienda (pero no ambas).

Pero parece que no puedo hacer que XC8 haga eso. He intentado varias combinaciones de desplazamiento por 8, o componentes, y máscaras, etc., y el código de ensamblaje más pequeño que puedo obtener proviene de una asignación directa seguida de un cambio xor:

union
{
    unsigned int i;
    struct
    {
        unsigned char lo;
        unsigned char hi;
    };
} address;

    address.i = Packet->dest_addr;
    address.hi ^= address.lo;   //xor swap: valA ^ valB = diff (bitwise difference, not arithmetic)
    address.lo ^= address.hi;   //xor swap: valA ^ diff = valB
    address.hi ^= address.lo;   //xor swap: valB ^ diff = valA

Pienso que la fuente del puntero ayudaría o no haría ninguna diferencia, dependiendo de si se aprovechó de las instrucciones del inc / decrement del puntero, pero insiste en recalcular el puntero para cada byte excepto para una asignación directa como esta.

¿Me estoy perdiendo algo?

(Incluí la etiqueta de alta tecnología porque XC8 desciende de Hi-Tech después de que Microchip la compró. ¿Quizás haya un viejo truco que aún funcione?)

    
pregunta AaronD

2 respuestas

2

Primero, si le interesan las instrucciones de la máquina, use el ensamblador.

En segundo lugar, si desea usar un esquema de codificación diferente al que utiliza el compilador para un entero de múltiples bytes, entonces podría declararlo como una matriz de bytes en primer lugar. De todos modos, el compilador no podrá operar en un entero con un byte invertido.

    
respondido por el Olin Lathrop
0

No tengo xc8.

Extendiendo tu código:

union Fubar
{
    unsigned int i;
    struct
    {
        unsigned char lo;
        unsigned char hi;
    };
};

    union Fubar address;
    unsigned int da = Packet->dest_addr;
    address.hi = ((union Fubar)da).lo;
    address.lo = ((union Fubar)da).hi;

o

    union Fubar address;
    address.hi = ((union Fubar)Packet->dest_addr).lo;
    address.lo = ((union Fubar)Packet->dest_addr).hi;

¿No es uno de esos más pequeños?

Espero que la segunda sea más lenta, porque vuelve a cargar cosas, si alguna parte de Packet->dest_addr es volatile .

Editar (incluso la alerta de Uglier):

union Fubar address;
unsigned char* const dp = &((unsigned char)Packet->dest_addr);
address.hi = dp[0];    // may need to swap the two destinations,
address.lo = dp[1];    // hi, lo, to get required byte order

Eso podría ayudar a que el compilador haga un mejor trabajo.

    
respondido por el gbulmer

Lea otras preguntas en las etiquetas