【问题标题】:8086 assembly division8086组装事业部
【发布时间】:2012-04-29 10:20:07
【问题描述】:

我在下面的代码中遇到了这个问题,它将数字转换为 ASCII '数字文本'。但是代码似乎在“div”操作码处循环

;Main Program
main:
    mov ax, 0x0000
    mov ds, ax ; setup data segment register
    mov si, GreetString ; setup data segment offset
    call print_string ; call print string procedure
    mov si, DataWord ; setup data segment offset
    mov bl, 0x000A ; base 10
    call format_string ; call format string procedure
    mov si, GreetString ; setup data segment offset
    call print_string ; call print string procedure
prevent_overflow:
    hlt ; halt the CPU
    jmp prevent_overflow

format_string:
mov ax, [ds:si] ; load register ax with data
xor cx, cx ; set counter to 0
mov si, GreetString ; set pointer to address of GreetString

.format_char:
div bl ; divides by register bl
add ah, 48 ; convert to ascii numeric
mov [ds:si], ah ; move ascii numeric to ds:si
inc cx ; increase counter
inc si ; increase si
xor ah, ah ; clear ah register
or ax, ax
jnz .format_char ; jump to format next char
ret

知道为什么会这样吗?我说“循环”是因为我的 CPU 处于最大值并且在 div 之后没有继续执行操作码

*已更新。谢谢纽格。添加了主要部分以使其更具可读性(^.^)

【问题讨论】:

  • bl有什么价值?你永远不会明确地分配它。
  • 是的,很抱歉。我确实在主要部分 mov bl, 0x000A 中分配了它; base 10 调用 format_string ;调用格式字符串过程

标签: assembly nasm x86-16


【解决方案1】:

问题是你得到一个除法溢出异常,因为商(在我下面的例子中是 12345 div 10 = 1234 + 5 的余数)不适合 al 的 8 位(请记住 ah是否已被其余部分使用?)。

每当商或余数不适合目标寄存器时,都会出现除法溢出异常。导致它的不仅仅是除以 0。

您想要进行 32/16=16:16 的除法,而不是 16/8=8:8 的除法。

这是我的更改在 DOS 中起作用的内容(标记为 ;;;):

; file: div2.asm
; compile as: nasm -f bin div2.asm -o div2.com
org 0x100 ;;;

;Main Program
main:
    mov ax, 0x0000
;    mov ds, ax ; setup data segment register ;;;
    mov si, GreetString ; setup data segment offset
    call print_string ; call print string procedure
    mov si, DataWord ; setup data segment offset
    mov bl, 0x000A ; base 10
    call format_string ; call format string procedure
    mov si, GreetString ; setup data segment offset
    call print_string ; call print string procedure

    ret ;;;

prevent_overflow:
    hlt ; halt the CPU
    jmp prevent_overflow

format_string:
mov ax, [ds:si] ; load register ax with data
xor cx, cx ; set counter to 0
mov si, GreetString ; set pointer to address of GreetString

.format_char:
; div bl ; divides by register bl ;;;
xor dx, dx ;;;
xor bh, bh ;;;
div bx ;;;

; add ah, 48 ; convert to ascii numeric ;;;
add dl, 48 ;;;

; mov [ds:si], ah ; move ascii numeric to ds:si ;;;
mov [ds:si], dl ; move ascii numeric to ds:si

inc cx ; increase counter
inc si ; increase si
; xor ah, ah ; clear ah register ;;;
or ax, ax
jnz .format_char ; jump to format next char

mov byte [ds:si], "$" ;;;
inc cx ; increase counter ;;;
inc si ; increase si ;;;

ret

print_string: ;;;
    pusha ;;;
    mov ah, 9 ;;;
    mov dx, si ;;;
    int 21h ;;;
    popa ;;;
    ret ;;;

DataWord dw 12345 ;;;
GreetString db "Hello World!", 13, 10, "$" ;;;

打印出来:

Hello World!
54321

【讨论】:

  • 非常感谢 Alex =D 这对我很有帮助!以为我仍然很困惑为什么会导致“循环”?
  • 如果默认除法异常处理程序(在 BIOS 或 DOS 中)简单地返回(使用 IRET),您会得到一个循环:DIV->异常处理程序->DIV->异常处理程序->DIV- >...处理程序不能做任何更合理的事情,因为它不“知道”这条指令在哪里(在什么程序或系统软件的一部分中)以及在每种情况下应该采取什么适当的行动。这是它所能做的最好的。但是,您可以重新定义处理程序并将适合您程序的逻辑放入其中。
  • 关于如何重新定义处理程序的任何建议或参考资料。它只是一个结构吗?
  • 这是一个例程,很像一个中断服务例程。它保留它修改的所有寄存器,完成它的工作,恢复寄存器,然后返回 IRET。阅读 Intel/AMD CPU 手册。请参阅有关中断和异常处理以及说明INTIRET 的部分。
  • 非常感谢 :D 将阅读有关它们的信息。希望我了解文档:D
猜你喜欢
  • 1970-01-01
  • 2015-03-07
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多