Pregunta

Tengo dos firmaron valores de 16 bits en una palabra de 32 bits, y necesito cambiar ellas derecha (división) de valor constante (que puede ser de 1 a 6) y saturar a byte (0..0xFF) .

Por ejemplo,

  • 0x FFE1 00AA con cambio = 5 debe convertirse 0x 0000 0005 ;
  • 0 x 2345 1234 debe convertirse en 0x 00FF 0091

Estoy tratando de saturar los valores al mismo tiempo, algo como esto pseudo-código:

AND RT, R0, 0x80008000; - mask high bits to get negatives
ORR RT, RT, LSR #1
ORR RT, RT, LSR #2
ORR RT, RT, LSR #4
ORR RT, RT, LSR #8; - now its expanded signs in each halfword
MVN RT, RT
AND R0, RT; now negative values are zero
; here something to saturate high overflow and shift after

pero el código que se ve es muy feo y lento. :) La mejor (más rápido) que tengo ahora es la saturación por separado de cada medio, de esta manera:

MOV RT, R0, LSL #16
MOVS RT, RT, ASR #16+5
MOVMI RT, #0
CMP RT, RT, #256
MOVCS RT, #255
MOVS R0, R0, ASR #16+5
MOVMI R0, #0
CMP R0, R0, #256
MOVCS R0, #255
ORR R0, RT, R0, LSL #16

Pero es de 10 ciclos. :( ¿Puede ser más rápido?

p.s .: Más tarde se encontró USAT16 instrucciones para esto, pero es sólo para ARMv6. Y necesito código para trabajar en ARMv5TE y ARMv4.


Editar ahora vuelvo a escribir mi primer código:

ANDS RT, 0x10000, R0 << 1;      // 0x10000 is in register. Sign (HI) moves to C flag, Sign (LO) is masked
SUBNE RT, RT, 1;            // Mask LO with 0xFFFF if it's negative
SUBCS RT, RT, 0x10000;      // Mask HI with 0xFFFF if it's negative
BIC R0, R0, RT;         // Negatives are 0 now. The mask can be used as XOR too
TST R0, 0xE0000000;         // check HI overflow             
ORRNE R0, R0, 0x1FE00000        // set HI to 0xFF (shifted) if so
TST R0, 0x0000E000          // check LO overflow             
ORRNE R0, R0, 0x00001FE0        // set LO to 0xFF if so          
AND R0, 0x00FF00FF, R0 >> 5;    // 0x00FF00FF is in register     

pero no es bella.

¿Fue útil?

Solución 2

Fue una buena idea usar una verificación para establecer banderas de dos operaciones. Pero no puedo hacerlo por segunda parte. Puedo hacer algo más :) Aquí está la variante universal a utilizar con cualquier cambio de 1 a 6:

;prepare:
MOV RMask, ((0xFF00 << shift) & 0xFF00) << 16;  Mask overflow bits
MOV R_0xFF00FF, 0xFF;
ORR R_0xFF00FF, 0xFF000000;
;...
; innerloop:
;....
TST R0, RMask, R0 << 16;            Set flags for LO half
ORRNE R0, R0, 0xFF << shift;        It is overflow. First try positive
BICMI R0, R0, 0xFF << shift;        Fix it if negative. LO half is ready
TST R0, RMask, R0;              Set flags for HI half. Can TST R0, R0, #Mask also
ORRNE R0, R0, 0xFF << (shift+16)
BICNE R0, R0, 0xFF << (shift+16)
AND R0, R_0xFF00FF, R0 >> shift;        Shift and mask

Por lo que es ahora 7 ciclos. :)

¿Puede ser mejor?


Editar se parece a desbordamientos son bastante raro, así que es una buena idea añadir algo como esto:

TST R0, 0xE000E000
BEQ no_saturation_needed
... ; saturation ops here

Otros consejos

Lo que tienes es casi tan bueno como vas a hacer por el problema como se indica. Si usted está haciendo esto para una gran cantidad de datos en un bucle estrecho, y puede permitirse unos pocos registros para mantener las máscaras, que puede ser capaz de ahorrar un ciclo o dos, pero no va a ser una gran mejora. No sólo no es un gran apoyo para este tipo de "pequeña vector" operación de saturación en ARM antes de la arquitectura V6.

Básicamente, a no ser que este es el único cuello de botella en su programa, es el momento de poner esta distancia y pasar al siguiente punto de acceso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top