Question

I ai deux valeurs signé de 16 bits en un mot de 32 bits, et je besoin de les déplacer à droite (division) de valeur constante (il peut être de 1 à 6) et à saturer octet (0..0xFF) .

Par exemple,

  • 0x FFE1 00AA avec décalage = 5 doit devenir 0x 0000 0005 ;
  • 0x 2345 1234 doit devenir 0x 00FF 0091

Je suis en train de saturer les valeurs en même temps, quelque chose comme ce pseudo-code:

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

mais le code que je reçois est très laid et lent. :) Le meilleur (le plus rapide) que j'ai maintenant la saturation séparée de chaque moitié, comme ceci:

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

Mais il est 10 cycles. :( Peut-il plus rapide?

p.s .: Plus tard, je trouve instruction USAT16 pour cela, mais il est seulement pour ARMv6. Et j'ai besoin du code pour travailler sur ARMv5TE et ARMv4.


Edit: maintenant je réécris mon premier code:

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     

mais il est pas beau.

Était-ce utile?

La solution 2

Il était une bonne idée d'utiliser un chèque pour définir des indicateurs pour deux opérations. Mais je ne peux pas le faire pour la deuxième partie. Je peux faire quelque chose d'autre :) est ici variante universelle à utiliser avec tout changement de 1 à 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

Il est donc 7 cycles maintenant. :)

Peut-il mieux?


Modifier ressemble trop-pleins sont assez rares, il est donc une bonne idée d'ajouter quelque chose comme ceci:

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

Autres conseils

Qu'est-ce que vous avez est à peu près aussi bon que vous allez faire pour le problème comme indiqué. Si vous faites cela pour un grand nombre de données dans une boucle serrée, et peut se permettre quelques registres à tenir des masques, vous pourriez être en mesure d'enregistrer un cycle ou deux, mais il ne va pas être une grande amélioration. Il est tout simplement pas un grand soutien pour ce type d'opération de saturation « petit vecteur » sur ARM avant l'architecture v6.

En fait, à moins que cela est le seul goulot d'étranglement dans votre programme, il est temps de mettre cette distance et de passer à la zone sensible suivante.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top