-1

My question pertains to a procedure that I wrote which takes the value in DX, converts it to decimal ASCII using an increment loop, and stores it in a string variable.

First, here is the string variable it is stored in:

;This string holds a 16 bit value represented in ascii decimal.
;the first byte is the starting char offset byte. It's used by the 
;procedure that prints it to determine which character to print first.  
;For instance the number "27" would have a starting char offset value of 4.
;This is done to avoid printing unnecessary leading zeros.
;eos is the end of string marker. It has a value of 0.

dec_str   db ?,"00000",eos        

And here is the procedure:

DX_2_DEC PROC

;CONVERTS A 16 BIT VALUE INTO DECIMAL ASCII CHARACTERS STORING IT
;AS A PRINTABLE STRING IN dec_str.

;EXPECTS THE 16 BIT HEX NUMBER IN DX.
;EXPECTS DS TO BE LOADED WITH DATA SEGMENT textSeg

    push ax
    push cx
    push di


    lea di, dec_str             ;ds:di -> textSeg:dec_str
    inc di                      ;skip past the starting char offset byte
    mov al, '0'                 ;initializing the string with 0's
    mov cx, 5                   ;writing 5 0's
INIT_STR_WITH_ZEROS:            
    mov BYTE PTR [di], al
    inc di
    loop INIT_STR_WITH_ZEROS    ;dec_str is now initialized.


    dec di                      ;dec back to the 5th ascii character

    test dx, 0ffffh             ;if dx = 0, then skip the inc loop
    jz SET_1S_                  ;and hop down to set the starting char
                                ;offset byte to 5

    mov cx, dx                  ;the given 16 bit value is the loop cntr
DECIMAL_ASCII_INC:

    inc BYTE PTR [di-0]         ;inc the 5th ascii char 
    cmp BYTE PTR [di-0], '9'    ;is the 5th character greater than a 9
    jbe INC_DEC_ASCII           ;if not, loop back & inc the 5th ascii char
    mov BYTE PTR [di-0], '0'    ;if so, reset 5th char to 0
    inc BYTE PTR [di-1]         ;and inc the 4th char
    cmp BYTE PTR [di-1], '9'    ;is the 4th character greater than a 9
    jbe INC_DEC_ASCII           ;if not, loop back & inc the 5th ascii char
    mov BYTE PTR [di-0], '0' 
    mov BYTE PTR [di-1], '0'    ;if so reset 5th & 4th char to 0    
    inc BYTE PTR [di-2]         ;and inc the 3rd char
    cmp BYTE PTR [di-2], '9'    ;is the 3rd character greater than a 9
    jbe INC_DEC_ASCII           ;if not, loop back & inc the 5th ascii char
    mov BYTE PTR [di-0], '0' 
    mov BYTE PTR [di-1], '0'
    mov BYTE PTR [di-2], '0'    ;if so reset 5th - 3rd char to 0
    inc BYTE PTR [di-3]         ;and inc the 2nd char
    cmp BYTE PTR [di-3], '9'    ;is the 2nd character greater than a 9
    jbe INC_DEC_ASCII           ;if not, loop back & inc the 5th ascii char
    mov BYTE PTR [di-0], '0'
    mov BYTE PTR [di-1], '0' 
    mov BYTE PTR [di-2], '0'
    mov BYTE PTR [di-3], '0'    ;if so reset 5th - 2nd char to 0
    inc BYTE PTR [di-4]         ;and inc the 1st char
    cmp BYTE PTR [di-4], '7'    ;1st can't be 7 or more (65,535 is the max)
    jb INC_DEC_ASCII            
    pop di
    pop cx
    pop ax
    ret


INC_DEC_ASCII:

    loop DECIMAL_ASCII_INC      ;loop until the ascii decimal characters
                                ;represent the value of the hexadecimal 
                                ;number in dx.                             


    jmp SET_DEC_LEN             ;skip the hop          
SET_1S_:                        ;need a hop since jump is out of range
    jmp SET_1S
SET_DEC_LEN:




    cmp dx, 10000d              
    jb CHK_1000S                ;if dx < 10,000 check the 1000s place value.
    mov BYTE PTR [di-5], 1      ;otherwise, starting char offset byte takes 1
    jmp DONE_WITH_DEC


CHK_1000S:
    cmp dx, 1000d               
    jb CHK_100S                 ;if dx < 1,000 check the 100s place value.
    mov BYTE PTR [di-5], 2      ;otherwise, starting char offset byte takes 2 
    jmp DONE_WITH_DEC


CHK_100S:
    cmp dx, 100d
    jb CHK_10S                  ;if dx < 100 check 10s place value.
    mov BYTE PTR [di-5], 3      ;otherwise, starting char offset byte takes 3
    jmp DONE_WITH_DEC


CHK_10S:
    cmp dx, 10d
    jb SET_1S                   ;if dx < 10 check 1s place value.
    mov BYTE PTR [di-5], 4      ;otherwise, starting char offset byte takes 4
    jmp DONE_WITH_DEC 


SET_1S:                         ;set to 1s place value.
    mov BYTE PTR [di-5], 5      ;starting char offset byte takes 5


DONE_WITH_DEC:



    pop di
    pop cx
    pop ax
    ret

DX_2_DEC ENDP        

This procedure works, it does convert DX into a decimal ascii string, but it doesn't always do it in the same amount of time. The greater the value in DX the longer the increment loop takes to execute. Converting hexadecimal, and binary to ascii is far easier, but each method is radically different. This procedure's sister procedures DX_2_HEX & DX_2_BIN do not resemble each other at all. However, DX_2_HEX and DX_2_BIN always take the same amount of time to execute, regardless of the actual size of the given 16 bit value. That's what i'm looking to do with this procedure.

I have a feeling I should be using binary coded decimal instructions, but after reading the intel 8086 programmer's reference I just don't see how they would be useful for converting a number from 0 through to 65,535 into decimal ascii. I can't find any example of a conversion process that can result in a decimal value greater than 9,999.

bad
  • 939
  • 6
  • 18
  • 1
    You can convert a 16-bit number to its decimal numeral with four divisions (by 10) by exploiting your fixed size buffer and string offset. Just store the remainders in reverse order (and the last quotient, or just do five divisions). – Margaret Bloom Nov 24 '17 at 17:02
  • Oh, okay. Thank you. I really don't why I couldn't find such a simple solution through Google. If you make it into an answer i'll award you the solution if you want it. – bad Nov 24 '17 at 17:05
  • https://stackoverflow.com/a/40505938/4271923 like this linked from https://stackoverflow.com/tags/x86/info? – Ped7g Nov 24 '17 at 21:04
  • I don't really see how those links are relevant, but ok. – bad Nov 24 '17 at 21:36
  • Check out [this great explanation on how to convert numbers into text](https://stackoverflow.com/questions/45904075/displaying-numbers-with-dos). Everything you need is in there. Even if something is tagged [tag:DOS], it can still apply anywhere. – Fifoernik Nov 25 '17 at 12:39
  • I was able to rewrite the code in a few minutes after @Margaret Bloom answered my question. This question is solved. – bad Nov 25 '17 at 16:45

1 Answers1

1
          mov     ax, dx
          lea     di, dec_str
          mov     cl, 5
          mov     bx, 100000
CONVERT:  xor     dx, dx
          div     bx
          add     al, 30h
          mov     si, dx
          mov     [di], al
          inc     di
          mov     ax, bx
          mov     bx, 0Ah
          xor     dx, dx
          div     bx
          mov     bx, ax
          mov     ax, si
          dec     cl
          jnz CONVERT