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
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).