我假设您已将 5 个字符('1'、'9'、'9'、'5'、'$')存储在名为 'ASCII' 的缓冲区中(请记住,5 个字符,包括终止 '$' 字节,我们需要它!)
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
我们读取每个字符,去掉最后一个 nybble(0-9 部分),并在乘以 10 后将其添加到我们的最终结果中。我们继续这样做,直到到达 '$' 分隔符。 (零更典型,但你正在学习,所以使用你想要的任何东西!耶!)
演练...
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!)
现在我想有人会告诉我关于将 cx 乘以 10 的古怪加法,但重复添加 cx(和 bx)比操纵 ax 更容易得到结果和dx 使用mul 10 指令...这会破坏我们在al 中的角色(数字!)还有总是其他方法可以做某事。这是可行的,这是可以理解的,不涉及扭曲逻辑以保持寄存器加载所需的值,并作为您可以做什么的示例。
此例程没有特定限制,尽管对于高于 65535. (2^16-1) 的值会变得很奇怪。查找Integer Overflow 以帮助了解原因。但它可以处理任意数量的数字(嗯,最多 5 个!),只要您使用 '$' 字符终止它们。
它不做负值,如果遇到的任何字符不是数字,它会给出古怪的结果(!%&$ 将返回 157,老实说!)。但这是另一天的教训。
当然,显示结果是另一个主题...我实际上已经在另一个问题中很好地介绍了它,使用 nasm 和 32 或 64 位指令(您在这里使用 16 位),但概念是相同的,大多数说明也是如此!看看here、here 和here。