简体   繁体   中英

Print from 1 to < user input in emu8086

I want to get a number (ie 5) from the user and then print starting from 1 to < input (ie 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
 MOV AH, 1 ; Get user input INT 21H 

If you input 5 then the AL register will hold the number 35h which is the ASCII code of that key. You clearly want what that key represents which is 5. You need to subtract 30h (48).

mov     ah, 01h  ; DOS.GetKey 
int     21h
sub     al, '0'
dec     al
mov     cl, al
mov     ch, 0

The rest of the program is fine for printing starting from 1 to < input.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM