Convert 16-bit decimal number to other bases using NASM assembly

I am having some problems implementing the correct decimal conversion to binary, octal and hex using NASM assembly. I have most of the code as shown below. I have some problems that I am still working on. I have commented out the relevant information in the code.

    %include "io.mac"
    .STACK 100H
    .DATA
    msg1        db "Please enter a positive integer (max 16 bits): ",0
    msg2        db "The binary (base-2) representation of the number is: ",0
    msg3        db "The octal (base-8) representation of the number is: ",0
    msg4        db "The hex (base-16) representation of the number is: ",0
    msg5        db "A",0 ;These will be implemented when I get the 
    msg6        db "B",0 ;hexadecimal loop working to change 10, 11, 
    msg7        db "C",0 ;etc. to their hex equivalents.
    msg8        db "D",0
    msg9        db "E",0
    msg10       db "F",0

    .UDATA
    num1            resw 1
    quotient        resw 1
    remainder       resw 1

    .CODE
    .STARTUP
    PutStr msg1
    nwln
    GetInt [num1]

    nwln
    PutStr msg2
    nwln
    mov AX, [num1]      
    sub BH, BH

    binary_loop:
    push AX 
    mov BH, byte 2 
    div BH ;All loops output the remainders in reverse order at the moment.
    mov [remainder], AH ;I was thinking of maybe moving the remainder value
    PutInt [remainder] ;to a stack then calling it at the end of the loop,
    mov [quotient], AL ;when the quotient value is zero. However,  
    mov AX, [quotient] ;I do not know enough to make that work. Any help
    cmp [quotient], byte 0 ;would be greatly appreciated
    jz binary_done ;Could also be je, as both do the same thing
    loop binary_loop

    binary_done:
    nwln
    PutStr msg3
    nwln
    mov AX, [num1]
    sub BH, BH      

    octal_loop:     
    push AX
    mov BH, byte 8
    div BH
    mov [remainder], AH
    PutInt [remainder]
    mov [quotient], AL
    mov AX, [quotient]
    cmp [quotient], byte 0
    jz octal_done
    loop octal_loop

    octal_done:
    nwln
    PutStr msg4
    nwln
    mov AX, [num1]      
    sub BH, BH  

    hex_loop:
    push AX
    mov BH, byte 16
    div BH
    mov [remainder], AH
    PutInt [remainder]
    mov [quotient], AL
    mov AX, [quotient]
    cmp [quotient], byte 0
    jz done
    loop hex_loop

    done:
    .EXIT

      

Current output for test 16-bit number 155: Binary: 11011001 Eighth: 332 Hex: 119

+3


source to share


1 answer


There are 3 main problems in your code:

  • It displays numbers in reverse order
  • It displays hex digits as whole numbers (e.g. 0xB is displayed as 11)
  • It is very badly commented (assembly is not high level language)

There are other problems in your code as well:

  • It's inefficient to use registers (store things in slower variables instead)
  • Duplicate code - the only procedure that takes "base" as input will halve the code size
  • Violation of macros ("language within a language"); which makes the code difficult to understand (for example, I can't tell if a PutInt

    function call or inline code, or which logs its use / trashes), and makes it impossible to optimize the instructions around it correctly


For the first problem, it is best to construct the string in memory in reverse order and then print the resulting string. For the second problem, you need to stop using PutInt

- every digit needs to be converted to a character.

For example (32-bit 80x86, NASM, untested):

;Convert unsigned integer to string
;
;Input
; eax = integer
; ebx = base
;
;Output
; edi = address of string
;
;Trashed
; eax,edx

    section .bss
tempString: resb 33              ;Worst case string size is 32 digits
                                 ; (for base2), plus string terminator
tempStringEnd:
    section .text

convertIntegerToString:
    mov byte [tempStringEnd-1],0 ;Store string terminator
    mov edi,tempStringEnd-2      ;edi = address to store last character

.nextDigit:
    xor edx,edx                  ;edx:eax = current value
    div ebx                      ;eax = new current value, edx = next digit
    add dl,'0'                   ;dl = character for next digit maybe
    cmp dl,'9'                   ;Is the character correct?
    jbe .gotChar                 ; yes
    add dl,'A'-'0'-10            ; no, fix it up
.gotChar:
    mov [edi],dl                 ;Store the character
    dec edi                      ;edi = address for next character
    test eax,eax                 ;Is the current value zero?
    jne .nextDigit               ; no, do the next digit

    ret                          ;Done, EDI = address of completed string

      

+2


source







All Articles