8086:使用输入值

时间:2014-06-30 13:30:42

标签: assembly x86 hex ascii x86-16

例如,我输入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年一起工作,即减去或增加它。

3 个答案:

答案 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)会更容易得到结果而不是操纵axdx来使用mul 10指令......这会破坏我们在al中保留的角色(数字!)有< em>总是其他做事方式。这是可行的,它是可以理解的,并不涉及扭曲逻辑以保持寄存器加载所需的值,并作为你可以做的事情的一个例子。

这个例程并没有特别的限制,尽管它对于65535以上的值会变得奇怪。(2 ^ 16-1)。查找Integer Overflow以了解原因。但只要您使用&#39; $&#39;来终止它们,它就可以处理任意数量的数字(最多5个!)。字符。

它没有做负值,如果遇到的任何字符都不是数字,它会给出古怪的结果(!%&amp; $将返回157,诚实!)。但那是另一天的教训。

当然,显示结果是另一个主题......我实际上在某个地方使用nasm和32或64位指令(你使用16位)很好地覆盖了它这里),但概念是相同的,大多数指令也是如此!查看hereherehere

答案 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