I am going to assume you have stored the 5 CHARACTERS ('1','9','9','5','$') in the buffer named 'ASCII' (remember, 5 chars, including the terminating '$' byte, we need that!)
ASC2DEC:
mov si, offset ASCII # this is where we get characters from
mov cx, 0 # zero register to hold final result
cvtchar:
mov al, [si] # get a character (30-39 representing 0-9, right?)
cmp al, '$' # are we done?
jz cvtdone # zero byte! (told you we needed that!)
add cx, cx # cx = cx * 2
mov cx, bx # bx = cx
add cx, cx # cx = cx * 2 (so now cx = cx * 4 overall)
add cx, cx # cx = cx * 2 (so now cx = cx * 8 overall)
add cx, bx # cx = cx + bx (so now cx = cx * 10 overall)
inc si # increment our pointer for next time
and ax, 0Fh # isolate the low nybble with the value (and zero rest of ax!)
add cx, ax # add new value to the final result
jmp cvtchar # do it again!
cvtdone:
mov ax, cx # obtain result in ax
We read each character, strip off the last nybble (the 0-9 part), and add that to our final result after multiplying by ten. We continue doing this until we reach the '$' delimiter. (a zero is more typical, but you're learning, so use whatever you want! yay!)
A walkthrough...
ASC2DEC:
si = offset ASCII
cx = 0
cvtchar:
al = [si] # = '1' = 31h
al == '$'? # nope!
cx = cx * 10 # essentially shift cx left one digit (right?) (and 0 * 10 = 0!)
si = si + 1 # bump pointer
ax = ax & 0fh # & = AND, so now ax = 1 (note how we skillfully zeroed rest of ax!)
cx = cx + ax # cx == 1!
jmp back to cvtchar...
cvtchar:
al = [si] # al = '9' = 39h
al == '$'? # nope!
cx = cx * 10 # so cx now = 1 * 10 = 10
si = si + 1 # bump pointer
ax = ax & 0fh # ax = 9
cx = cx + ax # cx = 19
jmp to cvtchar for another loop...
cvtchar:
al = [si] # al = '9' = 39h
al == '$'? # nope!
cx = cx * 10 # cx = 190
si = si + 1 # bump pointer
ax = ax & 0fh # ax = 9
cx = cx + ax # cx = 199
jmp to cvtchar (again!)
cvtchar:
al = [si] # al = '5' = 35h
al == '$'? # nope!
cx = cx * 10 # cx = 1990
si = si + 1 # bump pointer
ax = ax & 0fh # ax = 5
cx = cx + ax # cx = 1995
jmp to cvtchar (again!)
cvtchar:
al = [si] # al = '$' = 24h
al == '$'? # YES!
jmp cvtdone
cvtdone:
ax = cx # get our final result in ax (1995!)
Now I imagine someone is going to ping me about doing the wacky adding to multiply cx
by 10, but it's easier to repeatedly add cx
(and bx
) to get the result than to manipulate ax
and dx
to use the mul 10
instruction... which would destroy our character held in al
(the digit!) There are always other ways to do something. This works, it's understandable, doesn't involve warping the logic to keep the registers loaded with desired values and serves as an example of what you can do.
This routine doesn't have a particular limit, although it'll get weird for values above 65535. (2^16-1). Look up Integer Overflow to help understand why. But it'll handle any number of digits (well, up to 5!) as long as you terminate them with the '$' character.
It doesn't do negative values, and it'll give wacky results if any of the characters encountered are NOT digits (!%&$ will return 157, honest!). But that's a lesson for another day.
Of course, displaying the result is another topic... I've actually covered it nicely in another question somewhere, using nasm
and 32 or 64 bit instructions (you're using 16 bit here), but the concepts are identical, as are most of the instructions too! Look here, here, and here.