Reputation: 555
I'm new to assembly and the course that I follow uses EMU8086. I wrote this code to print Testing
and the ASCII code of 50 which is number 2
but it only prints Testing
and ignores the rest. What's wrong?
.model tiny
.code
org 100h
main proc
mov ah, 09h
mov dx, offset msg
int 21h
mov ah, 4ch
mov dx ,0
mov dl, 2
add dl, 48
int 21h
endp
msg db "Testing$"
end main
After reading the comments from @500 - Internal Server Error, I updated my code to this:
.model tiny
.code
org 100h
main proc
mov ah, 09h
mov dx, offset msg
int 21h
mov dl, 2
add dl, 48
int 21h
endp
msg db "Testing$"
end main
It still isn't working, so what's wrong?
Upvotes: 3
Views: 1756
Reputation: 47563
The DOS interrupt INT 21h/AH=9h doesn't take a character value to print, it takes the memory offset to the beginning of a $
terminated string to print.
DOS 1+ - WRITE STRING TO STANDARD OUTPUT
AH = 09h
DS:DX -> '$'-terminated string
Return:
AL = 24h (the '$' terminating the string, despite official docs which state that nothing is returned) (at least DOS 2.1-7.0 and NWDOS)
If you want to print out a single character with INT 21h/AH=9h then you'll need to move the value into a buffer that is terminated with a $
sign. You then pass the address of that buffer into INT 21h/AH=9h. Based on your second example something like this should work:
.model tiny
.code
org 100h
main proc
mov ah, 09h ; DOS Interrupt ah=9h print $ terminated string
mov dx, offset msg ; Address of msg
int 21h ; Int 21h/ah=9h Print msg
mov outchar, 48+2 ; Move ASCII val for `2` to outchar buffer
mov dx, offset outchar ; Address of the $ terminated outchar buffer in DX
int 21h ; AH is still 9h, so this prints $ terminated string
mov ax, 4c00h ; Exit program with return value 0
int 21h
endp
msg db "Testing$" ; msg string
outchar db ?, "$" ; output buffer for single character terminated with $
end main
Instead of mov outchar, 48+2
you could just use the ASCII value like this:
mov outchar, '2'
Alternatively you could do it with a single call to INT 21h/AH=9h by placing the character you want into the middle of an output buffer:
main proc
mov outchar, '2' ; Place the ASCII value for '2' in the output buffer
mov ah, 09h
mov dx, offset msg
int 21h ; Print $ terminated string starting at `msg`
mov ax, 4c00h
int 21h ; Exit with error code 0
endp
msg db "Testing"
outchar db ?, "$"
The reason this works is because INT 21h/AH=9h will blindly print everything it finds starting at offset msg
until it finds a $
terminating character. We effectively do the substitution of the character at outchar
first so that when INT 21h/AH=9h is executed it will encounter Testing2$
in memory.
Once it reaches the $
it will stop printing so the output would look like:
Testing2
You also have the option of using two different DOS (INT 21h) interrupts. While INT 21h/AH=9h prints a $
terminated string, INT 21h/AH=2h displays a single character:
DOS 1+ - WRITE CHARACTER TO STANDARD OUTPUT
AH = 02h
DL = character to write
Return: AL = last character output (despite the official docs which state nothing is returned) (at least DOS 2.1-7.0)
You could code your program to display the msg
string as you did, but then you can use INT 21h/AH=2h to display a single character. Your code could then look like this:
.model tiny
.code
org 100h
main proc
mov ah, 09h ; DOS Interrupt ah=9h print $ terminated string
mov dx, offset msg ; Address of msg
int 21h ; Int 21h/ah=9h Print msg
mov ah, 02h ; DOS interrupt ah=2h print single character
mov dl, '2' ; DL = ASCII value of character to print
int 21h ; Int 21h/ah=2h print single character in DL
mov ax, 4c00h ; Exit program with return value 0
int 21h
endp
msg db "Testing$" ; msg string
end main
Upvotes: 1
Reputation: 10371
Your second code is almost fine, you only forgot the service number in ah
to tell int 21h
what to do :
.model tiny
.code
org 100h
main proc
mov ah, 09h
mov dx, offset msg
int 21h
mov ah, 2 ;<==== AH=2 : INT 21H WILL DISPLAY CHARACTER IN DL.
mov dl, 2
add dl, 48
int 21h
endp
msg db "Testing$"
end main
Upvotes: 1