Revenir au plan du site


Astuces de manipulation de bits, calculs avec saturation, ...

Sources :
- Bit Twiddling Hacks
- cngsoft


Détecter si deux nombres ont un signe opposé
xor b
jp m,opposite

ou en fonction plus formelle (A=0 même signe, A!=0 signes opposés)
hasInverseSigns
xor b
ret m
xor a
ret

Effacer le bit à 1 le moins significatif d'un octet : X & (X-1)
ld b,a
dec a
and b
; test de sortie quand il n'y a plus de bit à 1

Cas pratique : Une table de tuiles à rafraichir. On élude naturellement les octets déjà à zéro
Note : Les performances sont meilleures quand il y a peu de bits à 1, rapport à inspecter tous les bits avec un ADD.
reloop ld a,(hl)
or a
jr z,next
tuileATraiter
exa
; on récupère la position du bit à 1 le plus faible dans une table de 256 octets
; la position dans la table peut tout aussi bien être un offset de la tuile à traiter (parmi les 8)
; on rafraichit notre tuile

; on efface le bit et on recommence si il reste un bit actif dans l'octet
exa : ld c,a : dec a : and c : jr nz,tuileATraiter
next
inc hl
djnz reloop

Addition 8 bits saturée à 255
add b
ld b,a
sbc a
or b ; #FF si débordement

Soustraction saturée à 0
sub b
ld b,a
sbc a
cpl ; inverser le masque dû à la carry
and b ; A=0 si débordement

Addition signée saturée -128/127
add b
jp po,_+
rlca ; récupérer le signe
sbc a ; #FF si résultat négatif, zéro sinon
xor #80 ; #7F pour saturation positive, #80 pour saturation négative
_

Soustraction signée saturée -128/127
sub b
jp po,_+
rlca ; récupérer le signe
sbc a ; #FF si résultat négatif, zéro sinon
xor #80 ; #7F pour saturation positive, #80 pour saturation négative
_

NEG saturé (flag P/V mis lors du traitement de #80)
neg
jp po,_+
dec a ; #80 devient #7F
_

Executer une routine 1 fois sur 2
.phase ld a,%10101010
rrca
ld (.phase+1),a
jr c,uneFoisSurDeux

Par extension du procédé, faire une action 1 fois sur 4 ou 3 fois sur 4
.phase ld a,%10001000 ; masque %01110111 pour 3 fois sur 4
rrca
ld (.phase+1),a
jr c,uneFoisSurQuatre

Même principe pour 1 fois sur 8
.phase ld a,%10000000 ; masque %11111110 pour 7 fois sur 8
rrca
ld (.phase+1),a
jr c,uneFoisSurHuit

Ajouter 8 bits non signés à HL (5 nops)
add l
ld l,a ; A+L
adc h ; A+L+H+carry
sub l ; H+carry (on enlève A+L)
ld h,a

Transformer le résultat d'une comparaison en masque
cp <valeur>
sbc a ; le résultat de la comparaison est un masque #00 ou #FF

Variante 1
cp <valeur>
sbc a ; le résultat de la comparaison est un masque #00 ou #FF
cpl   ; le résultat de la comparaison est un masque #FF ou #00

Variante 2
cp <valeur>
sbc a ; le résultat de la comparaison est un masque #00 ou #FF
inc a ; le résultat de la comparaison est un masque #00 ou #01

Enfin, le bit merge hack est décrit en cas pratique sur la page des [ passages de ligne, rebouclages écran ]

Bon code!