EMU 8086 在寄存器中存储了错误的数组元素值
EMU 8086 stores wrong array element value in register
.model small
.data
nizA db 1,2,3,4,5,6,7,8
nizB db 8 dup(?)
len equ 8
.code
main proc
mov si,0
mov di,0
mov cx,len
program:
mov al,nizA[si] ;problem is here it always stores CDh in AL
cbw ;convert AL to AX so i can divide
mov bl,2 ;The number I want to divide so I test if its even or not
div bl ;Overflow message
cmp ah,0
je next:
input:
mov dl,nizA[si]
mov nizB[di],dl
inc di
next:
add si,2
loop program
endp
end
我这里有这段代码,用于我需要做的期末考试,非常简单。从给定数组的偶数索引中查找奇数。所以这自然意味着我将 SI
增加 2,然后将该数组元素放入 AL
。但是无论数组中的数字是什么,AL
中存储的总是十六进制数字 CD,然后,如果它按预期存储,我想做 CBW
转换为 AX
并且能够除以 BL
我现在只有来自 EMU 8086 的错误消息说
divide error - overflow. to manually process this error, change
address of INT 0 in interrupt vector table.
肯定和CD号有关,我这里只有两个问题
- 存储 CD 而不是 1
- 溢出(很可能是因为 CD 太高了,但我仍然将数字分开,它们只会减少,所以有点意义不大)
您用 8
加载 cx
,因此您的循环将迭代 8 次。但是你在每次迭代中将 si
递增 2,所以在前 4 次迭代之后你已经超过了 nizA
数组的末尾。
尝试将 mov cx, len
替换为 mov cx, len/2
。
顺便说一句,检查 al
是否奇数的一种更简单、更有效的方法是 test al, 1
,它根据 al
的按位与设置标志1.
“正在存储 CD 而不是 1”
当 DOS .EXE 启动时,DS
段寄存器 而不是 指向您程序的 .data 部分! DS
段寄存器指向 ProgramSegmentPrefix aka PSP。这个 256 字节的区域是 DOS 保存有关 运行 程序的一些重要数据的地方,您可以在偏移地址 128.
处检索该程序的命令行。
您在代码 运行 时找到了值 CDh,因为它恰好是 PSP 中的第一个字节。它是始终开始 PSP 的 int 20h
指令的操作码。
你需要写的是:
.code
main proc
mov ax, @data
mov ds, ax
“溢出(很可能是因为 CD 太高了,但我仍然将数字分开,它们只会减少,所以有点不合理)”
其实很有道理。因为您使用 CBW
将被除数扩展到 AX
,并且因为 AL
中的值错误地为 CDh,所以 AX
中的新值变为 FFCDh。然后,当您的代码将其除以 2(使用 mov bl, 2
div bl
)时,商比除法专用商寄存器 AL
中可以存储的商大得多。这就是为什么您会收到“除法错误”的原因。
解决方案
- 这次验证除法有效的解决方案:
mov ax, @data
mov ds, ax
mov si, 0
mov di, 0
mov cx, len/2
program:
mov al, nizA[si]
mov ah, 0 ; For UNSIGNED division don't use CBW
mov bl, 2
div bl
cmp ah, 0 ; Remainder
je next
mov dl, nizA[si] ; Reload
mov nizB[di], dl
inc di
next:
add si, 2
loop program
- 避免分裂的解决方案有利于
TEST
并添加一些额外的改进:
mov ax, @data
mov ds, ax
xor si, si ; Better than 'mov si, 0` for zeroing a register
xor di, di ; idem
program:
mov al, nizA[si]
test al, 1
jz IsEven
mov nizB[di], al ; Only storing 'odd' values
inc di
IsEven:
add si, 2 ; Next 'even' index
cmp si, len
jb program
看看 TEST AL, 1
如何在 AL
寄存器上是非破坏性的,因此在写入 nizB[=54= 之前不需要重新加载值]数组?
另请注意,您并不总是需要单独的循环计数器。这里我使用了源数组索引。
.model small
.data
nizA db 1,2,3,4,5,6,7,8
nizB db 8 dup(?)
len equ 8
.code
main proc
mov si,0
mov di,0
mov cx,len
program:
mov al,nizA[si] ;problem is here it always stores CDh in AL
cbw ;convert AL to AX so i can divide
mov bl,2 ;The number I want to divide so I test if its even or not
div bl ;Overflow message
cmp ah,0
je next:
input:
mov dl,nizA[si]
mov nizB[di],dl
inc di
next:
add si,2
loop program
endp
end
我这里有这段代码,用于我需要做的期末考试,非常简单。从给定数组的偶数索引中查找奇数。所以这自然意味着我将 SI
增加 2,然后将该数组元素放入 AL
。但是无论数组中的数字是什么,AL
中存储的总是十六进制数字 CD,然后,如果它按预期存储,我想做 CBW
转换为 AX
并且能够除以 BL
我现在只有来自 EMU 8086 的错误消息说
divide error - overflow. to manually process this error, change address of INT 0 in interrupt vector table.
肯定和CD号有关,我这里只有两个问题
- 存储 CD 而不是 1
- 溢出(很可能是因为 CD 太高了,但我仍然将数字分开,它们只会减少,所以有点意义不大)
您用 8
加载 cx
,因此您的循环将迭代 8 次。但是你在每次迭代中将 si
递增 2,所以在前 4 次迭代之后你已经超过了 nizA
数组的末尾。
尝试将 mov cx, len
替换为 mov cx, len/2
。
顺便说一句,检查 al
是否奇数的一种更简单、更有效的方法是 test al, 1
,它根据 al
的按位与设置标志1.
“正在存储 CD 而不是 1”
当 DOS .EXE 启动时,DS
段寄存器 而不是 指向您程序的 .data 部分! DS
段寄存器指向 ProgramSegmentPrefix aka PSP。这个 256 字节的区域是 DOS 保存有关 运行 程序的一些重要数据的地方,您可以在偏移地址 128.
您在代码 运行 时找到了值 CDh,因为它恰好是 PSP 中的第一个字节。它是始终开始 PSP 的 int 20h
指令的操作码。
你需要写的是:
.code
main proc
mov ax, @data
mov ds, ax
“溢出(很可能是因为 CD 太高了,但我仍然将数字分开,它们只会减少,所以有点不合理)”
其实很有道理。因为您使用 CBW
将被除数扩展到 AX
,并且因为 AL
中的值错误地为 CDh,所以 AX
中的新值变为 FFCDh。然后,当您的代码将其除以 2(使用 mov bl, 2
div bl
)时,商比除法专用商寄存器 AL
中可以存储的商大得多。这就是为什么您会收到“除法错误”的原因。
解决方案
- 这次验证除法有效的解决方案:
mov ax, @data
mov ds, ax
mov si, 0
mov di, 0
mov cx, len/2
program:
mov al, nizA[si]
mov ah, 0 ; For UNSIGNED division don't use CBW
mov bl, 2
div bl
cmp ah, 0 ; Remainder
je next
mov dl, nizA[si] ; Reload
mov nizB[di], dl
inc di
next:
add si, 2
loop program
- 避免分裂的解决方案有利于
TEST
并添加一些额外的改进:
mov ax, @data
mov ds, ax
xor si, si ; Better than 'mov si, 0` for zeroing a register
xor di, di ; idem
program:
mov al, nizA[si]
test al, 1
jz IsEven
mov nizB[di], al ; Only storing 'odd' values
inc di
IsEven:
add si, 2 ; Next 'even' index
cmp si, len
jb program
看看 TEST AL, 1
如何在 AL
寄存器上是非破坏性的,因此在写入 nizB[=54= 之前不需要重新加载值]数组?
另请注意,您并不总是需要单独的循环计数器。这里我使用了源数组索引。