【问题标题】:8086: Working with values from input8086:使用来自输入的值
【发布时间】:2014-08-20 21:26:17
【问题描述】:

例如,我输入 1995。

在内存中,存储为31 39 39 35,即 1995 年的 ASCII。

然后我将其转换为十六进制,使其分离为13 5F (19 95)。 使用的代码是

mov ax, [memory location of first two bytes]
sub ax, 3030
aad

我的问题是,我该怎么做才能使它成为真正相当于 1995 年的 07CB,而不是分别为 19 和 95 的 13 5F?我想做的是将 1995 年作为一年,即从中减去或添加。

【问题讨论】:

  • 16 位值的最大高度是十进制 65535,如果我们想将该值精确转换为 16 位寄存器,那么我们必须将第一个最高转换的 ASCII 乘以十进制 10000 和第二高的 ASCII 1000 依此类推,最后我们必须将所有值加在一起。
  • 现在我不确定您是否想获得十进制或十六进制值的输出,或者如果您只想将值输入 16 位寄存器,则简单。我的答案仅显示获得十六进制输出。我希望这是你想知道的。

标签: assembly x86 hex ascii x86-16


【解决方案1】:

我已将工作分成两个不同的部分。一部分用于将十进制 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。

【讨论】:

  • 嗯,嗯...您正在将AX 中的值转换为存储在[ASCII] 中的4 位十六进制ASCII 输出。做得很好,但 OP 正在寻求将 ASCII 十进制数字([ASCII])转换为值(AX)以用于计算。不过,你有一个非常好的 value -> ASCII HEX 例程。干得好!
  • 我想我已经解释了将 ASCII 十进制数字(在 [ASCII] 中)转换为值(在 AX 中)的方法,我认为“user3044500”现在可以自行编程,如果这个新例程无法正常工作,则可以通过显示此新例程再次请求帮助。
【解决方案2】:

我假设您已将 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 位),但概念是相同的,大多数说明也是如此!看看hereherehere

【讨论】:

  • 示例乘为十:mov bx,ax shl ax,3 add bx,bx add ax,bx
【解决方案3】:

您的代码的问题在于 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-10
    • 2014-10-14
    • 1970-01-01
    • 1970-01-01
    • 2017-01-29
    • 2014-10-26
    • 2013-11-21
    • 1970-01-01
    相关资源
    最近更新 更多