Windows/DOS Assembly - Simple Math
Question
I'm currently learning Windows/DOS assembly. I'm just making a small program that adds two base 10 integers, and outputs the solution to standard output. Here is my current code:
org 100h
MOV al,5
ADD al,3
mov dx,al
mov ah,9
int 21h
ret
I'm confused as to why when that is compiled, I get the error:
error: invalid combination of opcode and operands
Because theoretically, all I'm doing is putting 5 into the AL register, adding three to it, taking the content of the AL register and putting it into the DX register for output, and then displaying it.
Any help would be appreciated, thanks!
Solution
DX
is a 16-bit register, but AL
is an 8-bit.
Load AL
into DL
, and set DH
to 0.
But that won't do what you want; function 9 [displays a null-terminated string]. You're telling it to display a string that starts at offset 9 of the data segment, which is probably going to be garbage.
You'll need to convert your answer into a series of digits first, and then call function 9.
There is some example code for converting the contents of a register to a string available. Copied here for reference, written by a user with the alias Bitdog.
; ------ WDDD = Write a Decimal Digit Dword at the cursor & a CRLF ------
;
; Call with, DX:AX = Dword value to print
; Returns, CF set on error, if DX:AX > 655359 max#
; (see WDECEAX.inc for larger number prints)
align 16
WDDD: CMP DX,10
JB WDDDok
STC ;CF=set
RET ;error DX:AX exceeded max value
WDDDok: PUSH AX
PUSH BX
PUSH CX
PUSH DX
XOR CX,CX ; clear count register for push count
MOV BX,10
WDDDnz: DIV BX ; divide DX:AX by BX=10
PUSH DX ; put least siginificant number (remainder) on stack
XOR DX,DX ; clear remainder reciever for next divide
OR AX,AX ; check to see if AX=number is divided to 0 yet
LOOPNE WDDDnz ; get another digit? count the pushes
MOV AH,2 ; function 2 for interupt 21h write digit
NEG CX ; two's compliment, reverse CX
MOV BL,48 ; '0'
WDDDwr: POP DX ; get digit to print, last pushed=most significant
ADD DL,BL ; convert remainder to ASCII character
INT 21h ; print ascii interupt 21h ( function 2 in AH )
LOOP WDDDwr ; deincrement CX, write another, if CX=0 we done
MOV DL,13 ; CR carriage return (AH=2 still)
INT 21h
MOV DL,10 ; LF line feed
INT 21h
POP DX
POP CX
POP BX
POP AX
CLC ;CF=clear, sucess
RET
; A divide error occurs if DX has any value
; when DIV trys to put the remainder into it
; after the DIVide is completed.
; So, DX:AX can be a larger number if the divisor is a larger number.