Search code examples
loopsassemblyemu8086

Print from 1 to < user input in emu8086


I want to get a number (i.e 5) from the user and then print starting from 1 to < input (i.e 1 2 3 4) But my code does not stop in "4" rather than the loop runs till "d"

I know that loop runs CX times and as in 8086 MOVZX does not work that is why at first I moved AL to CL then zeroed the CH.

As someone mentioned that the problem is as I am moving AL to CX I'm not moving the value 4, I'm moving 34(ASCII value of 4) and so my loop runs 34 times.

Now how do I convert my user input value to decimal and move that to CX. Is there any way to take user input that will be stored in AL as decimal value?

org 100h




MOV AH, 1  ; Get user input 
INT 21H


DEC AL ; Dec AL to satisfy the condition that it will print till < input

MOV BL,31H ; Initialize BL so that the output starts printing from 1 

MOV CL,Al ; set counter register CX 
MOV CH,00


Print:

MOV AH, 2    ; for output printing
MOV DL,0DH  ; for output printing
INT 21H      ; for output printing

MOV DL,0AH      ; for output printing
INT 21H            ; for output printing

MOV AH,2
MOV DL,BL         ; print what is in BL 
INT 21H

INC BL             ; then increment BL

LOOP Print     ; supposed to run the loop on Print what is the value in CL times

hlt

Solution

  • Now how do I convert my user input value to decimal and move that to CX.

    You've fallen into the trap of forgetting that loop conditions other than }while(--cx) are possible, using instructions other than loop.

    loop is just a peephole optimization for dec cx / jnz (without affecting FLAGS). Only use it when that's actually the most efficient way to loop. (Or just never use it at all, because you need to understand conditional branches anyway so omitting loop is one fewer instruction to learn about / remember. Also, on most modern x86 CPUs, loop is much slower than dec/jnz. It's good if tuning for real 8086, or optimizing for code-size over speed, though. But only necessary as an optimization.


    The easiest and most logically clear way to write this loop is:

        MOV AH, 1     ; read a char from stdin into AL
        INT 21H
    
        mov   cl, al    ; ending character
        mov   bl, '1'   ; b = current character, starting with '1'
    
    .top:                  ; do {
    
        ... print CR/LF   (not shown)
    
        mov   dl, bl
        int   21h            ; With AH=2 from printing CR/LF
    
        inc   bl             ; b++
        cmp   bl, cl
        jbe  .top          ; }while(b <= end_char);
    

    Notice that I increment after printing. If you increment before printing, you'd use jb for }while(b < end_char).


    On a real 8086, where loop is efficient, this does have more instructions and more code bytes inside the loop, and thus could be slower (if we consider a case where loop overhead matters, not with 3x slow int 21h system calls inside the loop).

    But that trades off against smaller total code size (from the trivial loop setup). So it's a tradeoff between static code size vs. dynamic instruction count (and amount of code bytes that need to be fetched, which was the real issue on 8086).