Ce code est 16bits mode réel.
Il permet de convertir un nombre mis dans AX vers une chaine de caractères dans DS:SI dans plusieurs bases :
-> Décimale
-> Hexadécimale
-> Binaire
-> Octale
Le code a été dévellopé avec TASM.
Source / Exemple :
MODEL SMALL
STACK 100h
DATA SEGMENT
Chaine DB 25 DUP ('$')
Prompt DB 'Conversion de $'
ChHexa DB 'en hexa :0x$'
ChDec DB 'en decimal :$'
ChBin DB 'en binaire :0b$'
ChOct DB 'en octal :0o$'
ChNeg DB 'en negatif :$'
CRLF DB 13,10,'$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
TerminalChar EQU '$'
;inverse une chaine
;==================
;DS:SI : adresse du début de la chaine
;DS:DI : adresse de fin de la chaine (avant le caractère de terminaison de chaine)
InverseChaine PROC
;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
boucleInv:
;on échange [DI] <-> [SI]
MOV AL,byte ptr [DI]
MOV AH,byte ptr [SI]
MOV byte ptr [SI],AL
MOV byte ptr [DI],AH
;octets suivants
DEC DI
INC SI
;tant que l'on n'a pas tout inversé (SI < DI)
CMP SI,DI
JL boucleInv
RET
InverseChaine ENDP
;convertit un nombre en sa représentation décimale (chaine)
;==========================================================
;DS:SI : adresse où stocker la chaine
;AX : nombre à convertir
;CX=1 : nombre signé, CX=0 : non signé
ChaineDec PROC
;sauvegarde des registres
PUSH DX
PUSH DI
PUSH CX
PUSH SI
PUSH AX
;si le nombre est non signé
CMP CX,0
;on passe à la conversion
JE PasSigne
;sinon, on calcule la valeur absolue
;si AX est >= 0
CMP AX,0
JGE PasSigne
;valeur absolue de AX
NEG AX
;on ajoute le signe
MOV byte ptr [SI],'-'
;on passe au caractère suivant
INC SI
PasSigne:
;sauvegarde de l'offset de départ de la chaine
MOV DI,SI
;mot de poids fort dans le dividende
XOR DX,DX
;tant qu'il y a des chiffres à ajouter
boucleDec:
;CX=AX pour le calcule du reste de division
MOV CX,AX
;division par 10 : algo de Terje Mathisen
;========================================
MOV DX,0CCCDh
;on divise AX par 10 : résultat dans DX
MUL DX
SHR DX,3
;========================================
;on sauvegarde de résultat dans AX
MOV AX,DX
;on calcule le reste de la division de CX(=AX avant division)
SHL DX,1 ;DX = quotient * 2
SUB CX,DX ;CX = divende - quotient * 2
SHL DX,2 ;DX = quotient * 2 * 4 = quotient * 8
SUB CX,DX ;CX = dividende - quotient * 2 - quotient * 8 = dividende - quotient * 10 = reste
;on ajoute '0'=48 pour convertir le chiffre en code ascii correspondant
ADD CX,'0'
;on le copie dans la chaine
MOV byte ptr [DI],CL
;on passe au caractère suivant
INC DI
;si le quotient est nul, on a fini la conversion
CMP AX,0
JA boucleDec
;on met un caractère de fin de chaine
MOV byte ptr [DI],TerminalChar
;on se place avant le caractère de la fin de chaine
DEC DI
;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
CALL InverseChaine
;récupération des registres
POP AX
POP SI
POP CX
POP DI
POP DX
RET
ChaineDec ENDP
;convertit un nombre en sa représentation héxadécimale (chaine)
;==============================================================
;DS:SI : adresse où stocker la chaine
;AX : nombre à convertir
;CX : nombre de digits
ChaineHex PROC
;sauvegarde des registres
PUSH DX
PUSH DI
PUSH CX
PUSH SI
PUSH AX
;sauvegarde de l'offset de départ de la chaine
MOV DI,SI
;tant qu'il y a des chiffres à ajouter
boucleHexa:
;DX=AX pour le calcul du reste de AX / 16
MOV DX,AX
;DX = reste de la division de AX par 16
AND DX,15 ;DX = AX and 01111b = AX mod 16
;on divise AX par 16 = 2 ^ 4
SHR AX,4
;le reste DX est-il entre 0 et 9
CMP DX,9
;si 9 < DX < 15
JA LettreHexa
;sinon, un chiffre
ADD DX,'0'
JMP MetChaine
;on doit afficher une lettre Hexadécimale
LettreHexa:
ADD DX,'A'-10
;on met le caractère dans la chaine
MetChaine:
MOV byte ptr [DI],DL
;on passe au caractère suivant
INC DI
;un digit affiché en plus
DEC CX
;si le quotient est nul, on a fini la conversion
CMP AX,0
JA boucleHexa
;s'il n'y a plus de digit '0' à ajouter devant le nombre
CMP CX,0
;on termine la chaine
JLE FinChaineHexa
;sinon, on ajoute les '0' manquants
boucle0Hexa:
;on met un "0"
MOV byte ptr [DI],'0'
;on passe au caractère suivant
INC DI
;tant que CX != 0
LOOP boucle0Hexa
;on ajoute le caractère de fin de chaine
FinChaineHexa:
;on met un caractère de fin de chaine
MOV byte ptr [DI],TerminalChar
;on se place avant le caractère de la fin de chaine
DEC DI
;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
CALL InverseChaine
;récupération des registres
POP AX
POP SI
POP CX
POP DI
POP DX
RET
ChaineHex ENDP
;convertit un nombre en sa représentation octale (chaine)
;==========================================================
;DS:SI : adresse où stocker la chaine
;AX : nombre à convertir
;CX : nombre de digits
ChaineOct PROC
;sauvegarde des registres
PUSH DX
PUSH DI
PUSH CX
PUSH SI
PUSH AX
;sauvegarde de l'offset de départ de la chaine
MOV DI,SI
;tant qu'il y a des chiffres à ajouter
boucleOct:
;on divise AX par 8 : quotient dans AX, reste dans DX (DL)
;calcul du reste
MOV DL,AL ;DL=AL
AND DL,07h ;DL = AL and 0111b = AL mod 8
;division par 2 ^ 3 = division par 8
SHR AX,3
;on ajoute '0'=48 pour convertir le chiffre en code ascii correspondant
ADD DL,'0'
;on le copie dans la chaine
MOV byte ptr [DI],DL
;on passe au caractère suivant
INC DI
;on a un digit de plus
DEC CX
;si le quotient est nul, on a fini la conversion
CMP AX,0
JA boucleOct
;s'il n'y a plus de digit '0' à ajouter devant le nombre
CMP CX,0
;on termine la chaine
JLE FinChaineOct
;sinon, on ajoute les '0' manquants
boucle0Oct:
;on met un "0"
MOV byte ptr [DI],'0'
;on passe au caractère suivant
INC DI
;tant que CX != 0
LOOP boucle0Oct
;on ajoute le caractère de fin de chaine
FinChaineOct:
;on met un caractère de fin de chaine
MOV byte ptr [DI],TerminalChar
;on se place avant le caractère de la fin de chaine
DEC DI
;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
CALL InverseChaine
;récupération des registres
POP AX
POP SI
POP CX
POP DI
POP DX
RET
ChaineOct ENDP
;convertit un nombre en sa représentation décimale (chaine)
;==========================================================
;DS:SI : adresse où stocker la chaine
;AX : nombre à convertir
ChaineBin PROC
;sauvegarde des registres
PUSH DX
PUSH DI
PUSH CX
PUSH SI
PUSH AX
;sauvegarde de l'offset de départ de la chaine
MOV DI,SI
;tant qu'il y a des chiffres à ajouter
boucleBin:
;on divise AX par 2 : quotient dans AX, reste dans DX (DL)
;calcul du reste
MOV DL,AL ;DL=AL
AND DL,1 ;DL=AL and 2 = AL mod 2
;division par 2
SHR AX,1
;on ajoute '0'=48 pour convertir le chiffre en code ascii correspondant
ADD DL,'0'
;on le copie dans la chaine
MOV byte ptr [DI],DL
;on passe au caractère suivant
INC DI
;on a un digit de plus
DEC CX
;si le quotient est nul, on a fini la conversion
CMP AX,0
JA boucleBin
;s'il n'y a plus de digit '0' à ajouter devant le nombre
CMP CX,0
;on termine la chaine
JLE FinChaineBin
;sinon, on ajoute les '0' manquants
boucle0Bin:
;on met un "0"
MOV byte ptr [DI],'0'
;on passe au caractère suivant
INC DI
;tant que CX != 0
LOOP boucle0Bin
;on ajoute le caractère de fin de chaine
FinChaineBin:
;on met un caractère de fin de chaine
MOV byte ptr [DI],TerminalChar
;on se place avant le caractère de la fin de chaine
DEC DI
;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
CALL InverseChaine
;récupération des registres
POP AX
POP SI
POP CX
POP DI
POP DX
RET
ChaineBin ENDP
;macro pour afficher une chaine à l'écran
Printf MACRO Chain
PUSH AX
MOV AH,09h ;fonction 9 : "puts"
LEA DX,Chain ;DS:DX : adresse de la chaine à afficher
INT 21h ;interruption DOS
POP AX
ENDM
;programme principal de test
Deb:
;init de DS
MOV AX,DATA
MOV DS,AX
;DS:SI : adresse de la chaine résultat
LEA SI,Chaine
;nombre à afficher
MOV AX,0FFF9h
;================
Printf Prompt
;affichage
;pas de signe
MOV CX,0
;conversion
CALL ChaineDec
Printf Chaine
Printf CRLF
;================
Printf ChDec
;affichage
;pas de signe
MOV CX,0
;conversion
CALL ChaineDec
Printf Chaine
Printf CRLF
;================
Printf ChHexa
;affichage
;4 digits
MOV CX,4
;conversion
CALL ChaineHex
Printf Chaine
Printf CRLF
;================
Printf ChOct
;affichage
;conversion
CALL ChaineOct
Printf Chaine
Printf CRLF
;================
Printf ChBin
;affichage
;16 digits
MOV CX,16
;conversion
CALL ChaineBin
Printf Chaine
Printf CRLF
;================
Printf ChNeg
;affichage
NEG AX
;un signe
MOV CX,1
;conversion
CALL ChaineDec
Printf Chaine
Printf CRLF
MOV AL,0
MOV AH,04Ch
INT 21h
CODE ENDS
END Deb
Conclusion :
N'hésitez pas à commenter et à noter...
Le code est commenté et optimisé (principalement DIV et MUL) dans les limites de mes connaissances...