assemblyx86-16dosemu8086

Cursor position not updating in 8086 Assembly language


.model small
org 100h

.data 
msg1 db "Enter a letter: $"
word db "BABA$"
word_length db 4 ; length of word
input1 db 10,?,10 dup('$') ; buffer for input
letter_pos db 0 ; counter for letter position

.code
main proc
    
    mov ah, 09h
    lea dx, msg1
    int 21h
    
    mov ah, 0ah
    lea dx, input1
    int 21h
    
    mov ah, 02h ; setting initial cursor position
    mov dh, 1
    mov dl, 0
    int 10h
 
    
    
    ; main code
    
    lea si, input1[2]
    lea di, word
    mov cl, word_length
    
compare:
    cmp cl, 0
    je exit
    mov bl, [si]
    mov bh, [di]
    cmp bl, bh
    je correct_letter
    inc letter_pos
    inc di
    dec cl
    jmp compare
    
    
correct_letter:
    ; set cursor position
    mov ah, 02h
    mov dh, 1
    mov dl, letter_pos
    int 10h
    
    mov ah, 09h
    lea dx, input1+2
    int 21h
    
    inc letter_pos
    mov al, letter_pos
    dec cl
    jmp compare
    




exit:
    MOV ah, 4ch
    int 21h
    
main endp
end main

I can't seem to work out why this doesn't work. I've set it so that every iteration of the loop, the letter_pos is incremented, meaning it will go the next column, or in this case to the next position of the word. Am I missing something here?

I'm very new to assembly language so pardon my mess of a code, I'm trying to learn this for a school project. Your help will be appreciated!

I'm expecting it to be like this:

Enter a letter: A
 A A

or

Enter a letter: B
B B

I tried some ways in an attempt to fix this, including changing 0rg 100g to .stack 100h (idk too much how this matters tho) and some other things, i'm still new so idk yet how to fully debug this.


Solution

  • Don't use org 100h when specifying any model other than .model tiny. The mention of org 100h means that you create a DOS executable file bearing the .COM extension. That's an excellent type of executable for anyone that is still new to assembly. The crucial benefit is that you don't need to worry about setting up the segment registers since at startup CS=DS=ES=SS, and that you can forget about .model, .data, .code, main proc, main endp, and end main.

    inc letter_pos
    mov al, letter_pos
    

    Here is why your program would hang if the loop weren't limited to just 4 iterations. This mov al, letter_pos needs to become inc di. Currently the program keeps re-testing the same matching character again and again.

    mov ah, 09h
    lea dx, input1+2
    int 21h
    

    And this is another peculiarity. Because you have used the DOS.BufferedInput funtion 0Ah for inputting that single character "A", the memory at input1+2 actually contains next 3 bytes: 65, 13, 36. So you will display the character "A" but the blinking cursor will return to the left side of the screen. That's one reason to get confused!

      org  100h            ; Create .COM program
    
      xor  dx, dx          ; Row DH=0, Column DL=0
      mov  ah, 02h         ; setting initial cursor position
      int  10h             ; BIOS.SetCursorPosition
      mov  dx, OFFSET msg
      mov  ah, 09h         ; DOS.PrintString
      int  21h
      mov  ah, 01h         ; DOS.KeyboardInputWithEcho
      int  21h             ; -> AL
      mov  bl, al          ; Move to a safe place (certainly not AL, AH, DL, DH)
    
      mov  di, OFFSET txt
      mov  cl, txt_length  ; 1+
    compare:
      cmp  bl, [di]
      jne  incorrect_letter
    correct_letter:
      mov  dh, 1
      mov  dl, letter_pos
      mov  ah, 02h
      int  10h             ; BIOS.SetCursorPosition
      mov  dl, bl
      mov  ah, 02h         ; DOS.DisplayOutput
      int  21h             ; -> AL
    incorrect_letter:
      inc  letter_pos
      inc  di
      dec  cl
      jnz  compare
    exit:
      mov  ax, 4C00h       ; DOS.TerminateWithReturncode
      int  21h
    ; --------------------
    ; The data comes below the code
    ; --------------------
    msg        db "Enter a letter: $"
    txt        db "BABA"
    txt_length db 4        ; length of word
    letter_pos db 0        ; counter for letter position
    

    I'm trying to learn this for a school project. Your help will be appreciated!

    The code that I present to you probably contains a lot of new stuff. If you're serious about 'learning this' then don't just copy-paste but look closely and keep asking yourself "Why did he choose to write it that way? Happy learning!