emu8086输入值用于计算,转换后的值仍为0

时间:2013-12-30 11:24:27

标签: assembly x86-16

我试图让这段代码工作,但是我一直在转换中遇到问题,我尝试了一些示例,这些示例是类似问题的答案,但是没有一个可以工作,但是从中我修补了一下我认为代码的版本,但它仍然无效。

org  100h

jmp calc


m1 db 0dh, 0ah, "Input width. $"
m2 db 0dh, 0ah, "Input perimeter. $"
m3 db 0dh, 0ah, "width= $"
m4 db 0dh, 0ah, "height= $"                     
width dw 8,0, 8 dup(0)
height dw 8,0, 8 dup(0) 

w dw 0
h dw 0


 calc: 
    mov dx, offset m1
    mov ah, 9                ;output message
    int 21h  

    mov dx, offset width
    mov ah, 0ah            ;read input for width
    int 21h
    mov si, offset width+2 

    xor bx, bx
    .next_digit1:
    xor ax, ax
    mov al, byte ptr [si]
    inc si
    cmp al, '0'
    jb .done1
    cmp al, '9'
    ja .done1
    sub al, '0'
    imul bx, 10               ;convert width string into a number
    add bx, ax
    jmp .next_digit1
    .done1:
    mov ax, bx
    mov w, ax


    mov dx, offset m3
    mov ah, 9                ;output message
    int 21h 
    mov ah, 2         ;output the result
    int 21h   

    mov ah, 0ah            ;read input for width
    int 21h

    mov dx, offset m2
    mov ah, 9                ;output message
    int 21h  

    mov dx, offset height
    mov ah, 0ah            ;read input for width
    int 21h
    mov si, offset height+2 

    xor bx, bx
    .next_digit2:
    xor ax, ax
    mov al, byte ptr [si]
    inc si
    cmp al, '0'
    jb .done2
    cmp cx, '9'
    ja .done2
    sub al, '0'
    imul bx, 10               ;convert width string into a number
    add bx, ax
    loop .next_digit2
    .done2:
    shr ax, 2
    sub ax, w
    mov h, ax


    mov dx, offset m4
    mov ah, 9                ;output message
    int 21h 
    mov ah, 2         ;output the result
    int 21h   

我有两个问题。

  1. 我显然是在为周边分区做错了,因为它给出了这个错误:

    划分错误 - 溢出。 手动处理此错误, 在中断向量表中更改INT 0的地址。

  2. 即使看起来它现在应该可以工作,但在所有处理之后,w和h似乎仍然等于0,即使它们应该等于用户输入的值。

2 个答案:

答案 0 :(得分:1)

Lemme对此表示不满......未经测试!

org  100h

jmp calc


m1 db 0dh, 0ah, "Input width. $"
m2 db 0dh, 0ah, "Input perimeter. $"
m3 db 0dh, 0ah, "width= $"
m4 db 0dh, 0ah, "height= $"                     
width dw 8,0, 8 dup(0)
height dw 8,0, 8 dup(0) 

w dw 0
h dw 0


calc: 
mov dx, offset m1
mov ah, 9                ;output message
int 21h  

mov dx, offset width
mov ah, 0ah            ;read input for width
int 21h
mov si, offset width+2 

xor bx, bx
.next_digit1:
xor ax, ax
mov al, byte ptr [si]
inc si
cmp al, '0'
jb .done1
cmp al, '9'
ja .done1
sub al, '0'
imul bx, 10               ;convert width string into a number
add bx, ax
jmp .next_digit1
.done1:
mov ax, bx
mov w, ax


mov dx, offset m3
mov ah, 9                ;output message
int 21h 
; I think you're good to here    

; this is meaningless - what's in dl?
mov ah, 2         ;output the result
int 21h   

; better load dx here, eh?
mov ah, 0ah            ;read input for width
int 21h
; in fact, don't do it here    

mov dx, offset m2
mov ah, 9                ;output message
int 21h  

mov dx, offset height
mov ah, 0ah            ;read input for width
; comment is wrong - no matter
int 21h
mov si, offset height+2 

xor bx, bx
.next_digit2:
xor ax, ax
mov al, byte ptr [si]
inc si
cmp al, '0'
jb .done2
cmp cx, '9'
ja .done2
sub al, '0'
imul bx, 10               ;convert width string into a number
add bx, ax
loop .next_digit2
.done2:
shr ax, 2
sub ax, w
mov h, ax


mov dx, offset m4
mov ah, 9                ;output message
int 21h 

; again, not what you want
mov ah, 2         ;output the result
int 21h   

我认为你已经将“转换字符串转换为数字”部分非常正确。现在,要输出结果,您必须“将数字转换为字符串”。你可能想要为字符串声明一个缓冲区,尽管一次可以打印一个字符。我们希望将数字重复除以10 - 记住div使用dx:ax。在div之后,商位于ax,余数位于dx。这是我们感兴趣的其余部分。不幸的是,我们将剩余部分“放在最右边”,我们希望首先打印“em”。有几种方法可以解决这个问题。最简单的可能是从缓冲区的“结束”(最右端)开始并“向后”工作。您可能希望使用'$'预先填充缓冲区,以便可以使用int 21h/9进行打印。一个16位数字最多可以使用五位数 - 你需要一个额外的'$'。从最后一个'$'开始,当你得到一个余数(它将在0到9之间,所以只在dl中)为它添加'0'(48或30h),并将其放入缓冲。如果商为零,我们就完成了。如果不是,则将索引递减(!)到缓冲区中并再次执行。当你完成后,你(可能)不会在缓冲区的开头,所以将你的索引转移到缓冲区到dx打印它。

另一种方法是将push每个剩余部分放到堆栈上 - 计算它 - 并按正确顺序关闭它们pop以一次打印一个。在之前或之后添加'0'。我喜欢这样的int 29h - 打印al没有副作用,但我不确定我们是否“应该”使用它。记录为“供内部使用”,我理解,但效果很好。 :)

除非我弄错了,emu8086包含一个调试器,这应该是一个很好的帮助!拉尔夫布朗的中断名单也将帮助你。在线版本是好的,但如果你下载整个混乱并“安装”它,有“奖金功能”(ports.lst.memory.lst等)。如果你正在做DOS(浪费时间,可以说),拉尔夫是你最好的朋友!兰迪海德的旧16位“装配艺术”也很好。 32位版本使用HLA语法,这是“完全不同”。我认为,16位版本应该与emu8086语法“非常接近”。

勇气!

答案 1 :(得分:0)

  

划分错误 - 溢出。要手动处理此错误,请在中断向量表中更改INT 0的地址。

表示除以零。您应该调试代码并检查实际处理的值。

此外:

mov ax, bx
mov bx, 2
div bx

注意div提供16位除数uses the pair DX:AX as dividend时。您似乎只划分AX的值,但不要将DX初始化为零。当除以2(或任何2的幂)时,使用右移也不是更容易(也更有效):

shr ax, 2   // performs a bitwise shift right, effectively dividing AX by two
  

即使看起来它现在应该可以工作,但在所有处理之后,w和h似乎仍然等于0,即使它们应该等于用户输入的值。

请查看function 0Ah of interrupt 21h的文档,因为它要求缓冲区采用特定格式:

  • 第一个字节保存缓冲区的容量
  • 第二个字节保存已用空间量:您应将其初始化为零

因此,如果你有一个8字节的缓冲区(8个字符),那么声明应如下所示:

# first byte = capacity of 8 characters; 
# second byte = zero to indicate the buffer is initially empty; this will receive the actual size of input read
# remaining eight bytes = the actual buffer, initialized to binary zeros (could be dup(?) as well)
buffer  db 8, 0, 8 dup(0)