3
\$\begingroup\$

I'm working on an exercise using Assembly 8086 which inputs a number (in string form) then output the binary form. Here is what I did (tested on emu8086 by the way):

  1. Convert the string to numeric form: I simply iterated through the string, and for each new value I simply multiply the old value by 10, then add by the new value. But there are some checks for overflow which was annoying: I have to check in both the multiplication and addition part, and since in this part I simply ignored the negative part (for simplicity) I had to check for a special case: a 16-bit signed number goes from \$-2^{15} = -32768\$ to \$2^{15} - 1 = 32767\$, so if the input is -32768 then there would be an error, so I had to check for that case specifically.

  2. From numeric to binary: I simply left-shifted the number (which is now stored in AX) consecutively and printed the most significant bit.

Please give some feedback, because I'm not sure if the overflow part is ok.

;Written by Dang Manh Truong
.stack      100h
.data
base10_string       dw      "-32799$"
biggest_16bits_signed       equ      7FFFh
special_16bits_signed       equ      8000h
special_16bits_signed_str   dw       "1000000000000000$"      
error_overflow      dw      "Arithmetic overflow encountered. Abort$"
error_not_a_number  dw      "Not a number. Abort$"
base10      equ     10 
tmp         dw      0
is_negative dw      0
.code
main        proc
;Initialization  
    mov     ax,@data
    mov     ds,ax  

;;;part 1: convert string to value
    mov     ax,0 ;number = 0;
    lea     si,base10_string
;check if positive or negative
    mov     bl,[si]  ;bl = value    
    cmp     bl,'+'
    jne     check_if_negative
    add     si,1    ;start from after the "+" sign
    mov     ax,0
    jmp     while_loop 
check_if_negative:
    cmp     bl,'-'   
    jne     check_if_not_a_number
    mov     ax,1
    mov     is_negative,ax
    mov     ax,0  
    add     si,1    ;start from after the "-" sign 
    jmp     while_loop
check_if_not_a_number:
    cmp     bl,'0'
    jge     keep_checking
    jmp     not_a_number
keep_checking:    
    cmp     bl,'9'
    jle     while_loop
    jmp     not_a_number
while_loop:
    mov     bl,[si]  ;bl = value  
    ;check if end of string      
    cmp     bl,'$'
    je      end_while 
    ;check if not a number
check_:
    cmp     bl,'0'
    jge     keep_checking_
    jmp     not_a_number
keep_checking_:
    cmp     bl,'9'
    jle     add_to_number
    jmp     not_a_number
add_to_number:   
    and     bx,000Fh ;'0'-> 0, '1' -> 1,...
    mov     dx,base10 
    ;try
    mul     dx       ;number = number*10
    ;catch (Exception ArithmeticOverflow)
    jo      overflow     
    ;try
    add     ax,bx    ;number = number*10 + value
    ;catch <Exception ArithmeticOverflow)
    ;jo      overflow
    cmp     is_negative,1
    jne     _perform_check
    cmp     ax,special_16bits_signed
    jne     _perform_check
    jmp     _aftercheck_overflow
_perform_check:    
    ;jo      overflow 
    cmp     ax,0
    jl      overflow
_aftercheck_overflow:
    add     si,1     ;next value   
    jmp     while_loop
end_while:          
;is negative?
    cmp     is_negative,1
    jne     begin_part2
    neg     ax
begin_part2:     
;;;part 2: print base-2 number
    mov     cx,16
    mov     bx,ax
    mov     ah,2
print_:
    cmp     cx,0
    je      after_print
    shl     bx,1 
;if bit == 1
    jnc     print_0 
;then print_1    
    mov     dl,'1'
    int     21h
    jmp     add_counter
;else print_0
print_0:
    mov     dl,'0'
    int     21h
add_counter:   
    dec     cx 
    jmp     print_
after_print:

    jmp     return_to_dos    
overflow:                
    lea     dx,error_overflow
    mov     ah,9
    int     21h
    jmp     return_to_dos        
not_a_number:  
    lea     dx,error_not_a_number
    mov     ah,9
    int     21h
    jmp     return_to_dos        
return_to_dos:
    mov     ah,4ch
    int     21h
main        endp
    end     main
\$\endgroup\$
3
\$\begingroup\$

One of the most problematic things to deal with in assembly and even other higher languages but to a lesser degree, is spaghetti code. The logic of the program becomes lost in scrolling back and forth through hundreds of lines, SO concise documentation of what is going in is essential.

Working from the inside out is a method that has worked very effectively for me.

; Read ASCII NULL terminated string and convert input to packed BCD.

      GetNext:    lodsb                  ; Read next character into AL
                  or      al, al         ; Teminator ?
                  jz      Done

                 .......

                 jmp     GetNext

       Done:

Sometimes you may even want to think of efficiency in terms of time. The most probable scenario is that you'd be encountering digits 0 to 9.

      GetNext:    lodsb                  ; Read next character into AL
                  cmp     al, '0'
                  jae     @F
                  cmp     al, '9'
                  jbe     @F
                  cmp     al, 0
                  jz      Done

    ; At this point we know our entry is invalid or alternately we might
    ; want to check for things like '+', '-' or in this case just ignore
    ; extraneous input.

                 jmp     GetNext

            @@:  ; This is peculiar to MASM and is a local label.
                 ; NASM it could be preceded with a period like .L0:

                 .......

                 jmp     GetNext

       Done:
\$\endgroup\$
  • \$\begingroup\$ Even better, range check with sub al, '0' / cmp al, 9 / ja non_digit(where you can also check for a terminating \0 by comparing against -'0'). Doing the whole range check with one compare is very nice, and it's a big win here because we actually want al - '0' to get the integer value of the digit. \$\endgroup\$ – Peter Cordes Nov 25 '17 at 5:08
  • \$\begingroup\$ Also, if you care about performance, lodsb is slower than movzx eax, byte [si] / inc si. (lodsd / lodsq are efficient on Haswell and later, only 2 uops, but not on earlier Intel or on AMD.) \$\endgroup\$ – Peter Cordes Nov 25 '17 at 5:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.