How can I print 0 to 100 in assembly language in emu 8086?
Asked Answered
N

2

6

Here I have tried something to print 10 to 0 decimal numbers in emu8086.

     .MODEL SMALL
     .STACK 100H
     .DATA
        NUM DB 58D

     .CODE
     MAIN PROC
          MOV AX,@DATA
          MOV DS,AX


     START:
         CMP NUM,48D 
         JGE PRINT
         JMP END_


     PRINT:
         MOV AH,2
         MOV DL,NUM
         INT 21H
         DEC NUM
         JMP START

     END_:
         MOV AH,4CH
         MAIN ENDP
     END MAIN

It works perfectly while printing 9 to 0 but it's not printing 10 instead the ascii character of value 10d. I am new in assembly language.so how can I print 0 to 100 decimal numbers?

Needle answered 3/6, 2016 at 4:15 Comment(3)
Possible duplicate of #15621758Dogma
Basically, you have to do the binary to decimal conversion by hand. This is what printf was always doing behind the scenes but now it's not there to help you out. Better start reading about DIV. Alternatively, make nested loops to print the units and 10s digits.Barge
It's printing ASCII character with value 58, which is ":". It's not printing any 10d value, that would be "new line feed" in ASCII. Also the 9 to 0 are not printing 0-9 values, but 48-57 values. Which are '0' to '9' digits in ASCII encoding. So if you want to do 100 to 0, you either have to make some algorithm working with 1 to 3 ASCII character values (48-57), or do the actual counting in integer form (from 100 to 0), and convert that number into 1 to 3 ASCII characters (48-57) as needed. As other comments are saying. (I just added this because you say "ascii character value of 10d" = nope)Gargoyle
C
5

The proper and generic solution to your problem is to convert the numbers into strings. To show you how to do it I made next changes to your code :

  • Changed the type of NUM, from DB to DW (required by number2string, it would hold bigger numbers).
  • Added variable numstr, which is NUM converted into string.
  • Added variable lbk (just a line break after each number).
  • Added proc number2string, to convert a number in AX to the string pointed by SI (this is the most important).
  • Added proc dollars, to fill numstr with dollar signs (necessary to display, and to clear the string before converting the next number).

Here is your code displaying numbers from 0 to 100 (the comments will help you to understand it) :

     .MODEL SMALL
     .STACK 100H
     .DATA
        NUM DW ?                                   
        lbk    db 13,10,'$'   ;LINE BREAK.
        numstr db '$$$$$'     ;STRING FOR 4 DIGITS.

     .CODE
     MAIN PROC
          MOV AX,@DATA
          MOV DS,AX

         MOV NUM, 0         ;FIRST NUMBER.
     START:
         CMP NUM, 100       ;IF NUM <= 100...
         JBE PRINT          ;...DISPLAY NUM.           
         JMP END_

     PRINT:
;         MOV AH,2            ;THIS CODE
;         MOV DL,NUM          ;DISPLAYS
;         INT 21H             ;ONE CHAR ONLY.

     ;CONVERT NUMBER TO STRING.
         mov  si, offset numstr
         mov  ax, num
         call number2string    ;RETURNS NUMSTR.

     ;DISPLAY STRING.
         mov  ah, 9
         mov  dx, offset numstr
         int 21h     

     ;DISPLAY LINE BREAK.
         mov  ah, 9
         mov  dx, offset lbk
         int 21h     

         INC NUM              ;NUM++.
         JMP START

     END_:
         MOV Ax,4C00H
         int 21h
         MAIN ENDP

;------------------------------------------
;CONVERT A NUMBER IN STRING.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (STR).
;PARAMETERS : AX = NUMBER TO CONVERT.
;             SI = POINTING WHERE TO STORE STRING.

number2string proc 
  call dollars ;FILL STRING WITH $.
  mov  bx, 10  ;DIGITS ARE EXTRACTED DIVIDING BY 10.
  mov  cx, 0   ;COUNTER FOR EXTRACTED DIGITS.
cycle1:       
  mov  dx, 0   ;NECESSARY TO DIVIDE BY BX.
  div  bx      ;DX:AX / 10 = AX:QUOTIENT DX:REMAINDER.
  push dx      ;PRESERVE DIGIT EXTRACTED FOR LATER.
  inc  cx      ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
  cmp  ax, 0   ;IF NUMBER IS
  jne  cycle1  ;NOT ZERO, LOOP. 
;NOW RETRIEVE PUSHED DIGITS.
cycle2:  
  pop  dx        
  add  dl, 48  ;CONVERT DIGIT TO CHARACTER.
  mov  [ si ], dl
  inc  si
  loop cycle2  

  ret
number2string endp       

;------------------------------------------
;FILLS VARIABLE WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THE STRING WILL BE DISPLAYED.
;PARAMETER : SI = POINTING TO STRING TO FILL.

proc dollars                 
  mov  cx, 5
  mov  di, offset numstr
dollars_loop:      
  mov  bl, '$'
  mov  [ di ], bl
  inc  di
  loop dollars_loop

  ret
endp  

;------------------------------------------

     END MAIN

From now on you can use number2string and dollars to display numbers.

Clairvoyance answered 3/6, 2016 at 15:57 Comment(1)
Thank you very much for your help.Needle
A
1

I know,it's been 5 years. But This may be helpful to others.

; Here at first, @ indicating start of label and $ indicating start of procedure. if multiple label and procedure is present in assembly code.
; Then distinguishing label & procedure can be done easily. It's just my own way of coding. You can ignore this style

;Algorthm for Decimal Input

;   number = 0
;   while input != "\n" do
;         number = number * 10
;         input a charchter
;         number = number + input
;         count++

;Algorthm for Decimal Output
;   for i = 1 to count do 
;       reminder = number % 10
;       push reminder
;
;   for i = 1 to count do
;       pop reminder
;       print reminder


.model small    ; declaring this code will be consists of one data segment and one code segment
.stack 100h     ; stack is initializeed to offset address at 100h

.data           ; this is data segment

n_line db 0ah,0dh,"$"  ;here declared a string named n_line which is define byte(8 bit), which value is null('$')
                       ;and 0ah is for line feed (moves to next output line) & 0dh is for carriage return

n dw ?              ; n is defne word(16 bit) variable which value is not initialized yet
i db ?              ; i is define byte(8 bit) variable which value is not initialized yet
count db ?          ; i is define byte(8 bit) variable which value is not initialized yet
reminder db ? ;reminder is define byte(8 bit) variable which value is not initialized yet
flag db 0       ;flag   is define byte(8 bit) variable which value is initialized as 0
num dw ?         ; num  is defne word(16 bit) variable which value is not initialized yet

.code    

$set_number proc     
    @while: 
        mov ah,1     ; taking input here
        int 21h  
        mov cl,al
        sub cl,30h  
            
        cmp al,13  ;checking if input is new line or not
        
        je @break_while
            mov ax,n   ; al = n
            mul bl     ; al = n * 10
            mov n,ax   ;  n = n * 10     
            
            mov ch,0   ;as n variable is dw so...
            add n,cx  ; n = n + al = (n * 10) + al
                        
        inc count     ; count = count + 1
        jmp @while 
    @break_while:         
    ret            ; here instruction pointer will jump to the next line of calling this procedure
$set_number endp   ; end of procedure


$get_number proc
    @for_loop_1_init:
        mov i,1d       
    @for_loop_1:
        mov dl,count     ; before executing loop,every time i'm storing count variable to al register
        cmp i,dl         ; it means here, cmp i,count 
        jg @for_loop_1_end  
            mov ah,0     ; here chances may be ah store some value,so clearing ah register
            cmp flag,0   ; think like boolean value
            jne @try     ; suppose, n = 135d .So each time,i'm ensuring quotient is divded & excluding reminder from ah register  
            mov ax,n  
            mov flag,1 
            div bl       ; al = ax/bl  and ah = reminder 
            jmp @final
            @try:
                mov ah,0
                div bl
            @final:    
            xor cx,cx    ; clearing cx register
            mov cl,ah
            
            push cx   ;push reminder

        inc i
        jmp @for_loop_1 
    @for_loop_1_end:
    
    ; uncomment these, if you want to print in row wise 
    ;    lea dx,n_line
    ;    mov ah,9
    ;    int 21h
                    
    @for_loop_2_init:
        mov i,1d       
    @for_loop_2:
        mov al,count     ;before executing loop,every time i'm storing count variable to al register
        cmp i,al         ;it means here, cmp i,count 
        jg @for_loop_2_end  
            
            pop dx    ;stack's top value is stored in dx now
             
            add dx,30h  ; 30h is equivalent to 48d, means ascii charchter 0
            mov ah,2
            int 21h
    
        inc i
        jmp @for_loop_2 
    @for_loop_2_end:        
                           
    ret     ; here instruction pointer will jump to the next line of calling this procedure
$get_number endp   ; end of procedure

main proc
    mov ax,@data    
    mov ds,ax    
    
    mov bl,10d  ; bl = 10d
@input:
    xor cx,cx   ; clearing cx register

    call $set_number
@print:
    cmp n,0
    je @stop
        
    xor ax,ax   ; clearing ax register
    xor cx,cx   ; clearing cx register
    xor dx,dx   ; clearing dx register
    
    call $get_number  
    
    mov dl,32d   ; 32d is for space in ascii
    mov ah,2
    int 21h 
    
    ;These register can be affected so for futher looping,clearing all 
    
    xor ax,ax   ; clearing ax register
    xor cx,cx   ; clearing cx register
    xor dx,dx   ; clearing dx register
    mov count,0
    mov flag,0
    
    dec n       ; This Question was to print number in decreasing order
    mov ax,n
    @repeat:    ;in this label,i am counting length of n
        mov ah,0
        div bl
        
        inc count    
    cmp al,0
    jnle @repeat
    
    jmp @print
              
  
@stop:     
    mov ah,4ch ; terminate the programme
    int 21h     
main endp      ; ending of main procedure
end main       ; ending of code segment

Output will be look like this, if input = 105
if input = 105

Atom answered 24/5, 2021 at 12:50 Comment(1)
You don't need to separately count the number of decimal digits; and then loop to generate them; you should use both remainder and quotient outputs from one div. e.g. Displaying numbers with DOS. Or How do I print an integer in Assembly Level Programming without printf from the c library? shows some efficient ways in C and 32-bit asm; porting the actual loop to 16-bit should be simple. You also don't need static storage for things like n; use a register, that's what they're for.Daria

© 2022 - 2024 — McMap. All rights reserved.