How to convert binary into decimal in assembly x8086?

1.9k views Asked by At

I find some code really works, but I don't know why this code works.

why combining RCL and ADC could convert the binary to decimal, is this algorithm a nice one?

how to explain this, are there any better code?

;input=R5R6R7
;output=buffer0 - buffer7

DATA    SEGMENT

    R0      DW      (?)     ;0000H
    R1      DW      (?)     ;0002H
    R2      DW      (?)     ;0004H
    R3      DW      (?)     ;0006H
    R4      DW      (?)     ;0008H
    R5      DW      (?)     ;000AH
    R6      DW      (?)     ;000CH
    R7      DW      (?)     ;000EH

    buffer0 DB      (?)     ;001CH
    buffer1 DB      (?)
    buffer2 DB      (?)
    buffer3 DB      (?)
    buffer4 DB      (?)
    buffer5 DB      (?)
    buffer6 DB      (?)
    buffer7 DB      (?)
    buffer8 DB      (?)
    buffer9 DB      (?)

DATA    ENDS


BCTD    PROC    NEAR
    MOV     CX, 8
    LEA     BX, [buffer0]

CLR_BUFFER:
    MOV     BYTE PTR [BX], 0
    INC     BX
    LOOP    CLR_BUFFER

    MOV     CX, 48
BCTD_LOOP:
    CLC
    RCL     R7, 1
    RCL     R6, 1
    RCL     R5, 1

    MOV     AL, buffer0
    ADC     AL, AL
    DAA
    MOV     buffer0, AL

    MOV     AL, buffer1
    ADC     AL, AL
    DAA
    MOV     buffer1, AL

    MOV     AL, buffer2
    ADC     AL, AL
    DAA
    MOV     buffer2, AL

    MOV     AL, buffer3
    ADC     AL, AL
    DAA
    MOV     buffer3, AL

    MOV     AL, buffer4
    ADC     AL, AL
    DAA
    MOV     buffer4, AL

    MOV     AL, buffer5
    ADC     AL, AL
    DAA
    MOV     buffer5, AL

    MOV     AL, buffer6
    ADC     AL, AL
    DAA
    MOV     buffer6, AL

    MOV     AL, buffer7
    ADC     AL, AL
    DAA
    MOV     buffer7, AL

    LOOP    BCTD_LOOP
    RET
BCTD    ENDP
1

There are 1 answers

0
rkhb On BEST ANSWER

buffer[] holds the result (packed BCD) which is initially set to 0. At every shift-left of the 48-bit integer (RCL...RCL...RCL) the result is multiplied by 2 and the isolated binary digit (shifted bit) is added (ADC AL, AL). The principle is the same as with converting a decimal number into an integer (multiply by ten and add the isolated decimal digit). DAA handles the overflows after an addition. The carry of the very first ADC comes from the last RCL, but the following ADC take the carry flags from DAA.

Advantage:

  • No divisions.
  • The code can easily be adjusted for bigger integers.

Disadvantage:

  • The result is BCD-packed. You need some effort to convert it into a decimal ASCII-string.
  • Leading zeros.
  • The loop has to run over the whole amount of bits in every case. This is expensive for smaller integers.

BTW: Your "input" is handled as "big endian", while "buffer" results in "little endian". You will be in trouble at least when you want to play with 32-bit registers (e.g. EAX - yes, you can address them in 16-bit mode).