Les opérations arithmétiques s’appuient principalement sur les 2 instructions add et sub déclinées dans leur mode litéral ou registre. Si add ne pose pas de problème particulier, sub quant a elle peut en dérouter plus d’un car elle opère sur l’opposé de W comme indiqué ci-après :
sublw 0xa sublw 10 ; W = 10 – W |
subwf 0x20, f subwf R_2_MAX_TX ; R_2_MAX_TX = R_2_MAX_TX – W |
De plus, l’unité arithmétique et logique des PIC16 ne propose pas d’instruction de comparaison qui peut être considéré comme un manque notoire dans leur jeu d’instructions mais nous allons voir au travers de deux exemples de traitements classiques que l’on peut très bien s’en passer en faisant un peu d’arithmétique modulo 256 :
- La conversion d’un quartet compris entre 0 et 15 en un caractère hexadécimal codé en ASCII [0-9A-F]
- La détermination de la plage à laquelle appartient une valeur donnée comprise entre 0 et 255
Pour chaque exemple, il sera proposée la version « optimisée » dans laquelle aucun registre intermédiaire ou temporaire n’est utilisé comme si l’instruction de comparaison était disponible.
- Conversion d’un quartet en un caractère hexadécimal codé en ASCII
Tout d’abord ci-après une implémentation possible sans opération arithmétique permettant de bien comprendre l’expression du besoin :
. . . |
movf 0x7f, w movf R_NIBBLE_TO_CONVERT,w ; W = Quartet à convertir |
call 0x100 call nibble_to_ascii |
. . . ; W = Valeur HEXA codée en ASCII [0-9A-F] |
org 0x100 |
nibble_to_ascii ; Peut s’exécuter depuis n’importe quel BANK |
clrf 0xa clrf SFR_PCLATH ; Init. PCLATH sans altérer W |
bsf 0xa, 0 bsf SFR_PCLATH,0 ; Définitions dans la page 0x01 |
andlw 0xf andlw 0x0F ; Abandon du nibble haut |
addwf 0x2, f addwf SFR_PCL |
retlw 0x30 retlw ‘0’ ; Liste des 16 codes ASCII |
retlw 0x31 retlw ‘1’ |
retlw 0x32 retlw ‘2’ |
retlw 0x33 retlw ‘3’ |
retlw 0x34 retlw ‘4’ |
retlw 0x35 retlw ‘5’ |
retlw 0x36 retlw ‘6’ |
retlw 0x37 retlw ‘7’ |
retlw 0x38 retlw ‘8’ |
retlw 0x39 retlw ‘9’ |
retlw 0x41 retlw ‘A’ |
retlw 0x42 retlw ‘B’ |
retlw 0x43 retlw ‘C’ |
retlw 0x44 retlw ‘D’ |
retlw 0x45 retlw ‘E’ |
retlw 0x46 retlw ‘F’ |
org 0x100 |
nibble_to_ascii ; VAL = W à convertir |
andlw 0xf andlw 0x0F ; Abandon du nibble haut |
sublw 0x9 sublw (0x0A – 1) ; W = (0x09 – VAL) |
btfsc 0x3, 0 skpnc ; Test autour du pivot 0x09 |
goto 0x106 goto nibble_to_ascii_0_9 |
nibble_to_ascii_A_F |
; VAL >= 0x0A : return VAL + 0x37 (0x37 = ‘A’ – 0xA) |
sublw 0x40 sublw 0x40 ; W = 0x40 – (0x09 – VAL) |
return return ; = VAL + 0x37 |
nibble_to_ascii_0_9 |
; VAL < 0x0A : return VAL + ‘0’ |
sublw 0x39 sublw ‘9’ ; W = ‘9’ – (0x09 – VAL) |
return return ; = VAL + 0x30 = VAL + ‘0’ |
Maintenant, pourquoi ne pas pousser le raisonnement plus en avant en supprimant le ‘goto nibble_to_ascii_0_9‘ et le premier ‘return ; = VAL + 0x37‘. Pour cela, il suffit de les remplacer par une opération arithmétique qui « annule » le traitement fait en « trop » puis regrouper les opérations successives. Nous arrivons alors à l’implémentation suivante qui est encore moins coûteuse que la précédente :
org 0x100 |
nibble_to_ascii ; VAL = W à convertir |
andlw 0xf andlw 0x0F ; Abandon du nibble haut |
sublw 0x9 sublw (0x0A – 1) ; W = (0x09 – VAL) |
btfsc 0x3, 0 skpnc ; Test autour du pivot 0x09 |
addlw 0x7 addlw 7 ; VAL < 0x0A uniquement |
sublw 0x40 sublw (0x37 + 9) ; Si VAL < 0x0A => return VAL + ‘0’ |
return return ; Sinon => return VAL + (‘A’ – 0x0A) |
Pages: 1 2