例如,我输入1995。
在内存中,它存储为31 39 39 35
,即1995年的ASCII。
然后我将它转换为十六进制,因此它被分成13 5F
(19 95)。
使用的代码是
mov ax, [memory location of first two bytes]
sub ax, 3030
aad
我的问题是,我该如何做到07CB,真正相当于1995年,而不是13 5F,分别是19和95?我想做的是与1995年一起工作,即减去或增加它。
答案 0 :(得分:0)
我把工作分成了两个不同的部分。一部分用于将十进制ASCII(使用十进制值系统)转换为AX寄存器,并将这些值相乘并相加。另一部分是将AX中的值转换为十六进制ASCII,并将结果存储在保留的内存位置。以下是第二部分的代码示例:
ASCII DB "0000", "$"
mov di, OFFSET ASCII
mov cl, 4
A: rol ax, 4
mov bl, al
and bl, 0Fh ; only low nibble of byte
add bl, 30h
cmp bl, 39h ; avove "9"
jna short B
add bl, 7 ; then letter from "A" to "F"
B: mov [di], bl
inc di
dec cl
jnz A
这个例程可以简单地增强32位寄存器。只需使用" mov cl,8" +" A:rol eax,4" + ASCII DB" 00000000"," $"并且对于8位寄存器也很简单,只能获得2个ASCII。
答案 1 :(得分:0)
我假设你已经存储了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
中保留的角色(数字!)有< em>总是其他做事方式。这是可行的,它是可以理解的,并不涉及扭曲逻辑以保持寄存器加载所需的值,并作为你可以做的事情的一个例子。
这个例程并没有特别的限制,尽管它对于65535以上的值会变得奇怪。(2 ^ 16-1)。查找Integer Overflow以了解原因。但只要您使用&#39; $&#39;来终止它们,它就可以处理任意数量的数字(最多5个!)。字符。
它没有做负值,如果遇到的任何字符都不是数字,它会给出古怪的结果(!%&amp; $将返回157,诚实!)。但那是另一天的教训。
当然,显示结果是另一个主题......我实际上在某个地方使用nasm
和32或64位指令(你使用16位)很好地覆盖了它这里),但概念是相同的,大多数指令也是如此!查看here,here和here。
答案 2 :(得分:0)
您的代码存在的问题是,aad
指令要求高位数字位于ah
,而al
位置处于低位。您的mov ax
指令会以错误的顺序获取它们。要解决此问题,请尝试:
mov ax, [buf]
sub ax, 3030
xchg ah, al
aad ; `al` now holds 10 * 1 + 9
为了累积1995年的全部价值,你可以从这里继续:
mov ah, 100
mul ah ; `ax` now holds 1900
mov bx, ax ; save
mov ax [buf+2]
sub ax, 3030
xchg ah, al
aad
add bx, ax ; bx now holds 1995