ASM x86 中的长除法
Long division in ASM x86
我正在编写一个 ASM 程序,将两个数字相除并计算小数点后 20 位。我的策略是通过长除法过程计算下一个数字并将它们压入堆栈。然后获取堆栈指针,从中减去 20 位 * 8 位并从该地址写入数字,然后将 8 添加到该地址,写入该数字等。但是当我尝试它时它只写出零。这些数字在堆栈上,因为我只尝试 "popping" 它们并且工作正常。我只需要它们以与它们被推入时相同的顺序弹出,而不是颠倒。
我的代码:
dane SEGMENT ;segment danych
text db 0dh, 0ah,"Give b (a/b)", 0dh, 0ah, "$"
text2 db 0dh, 0ah,"Give a (a/b)", 0dh, 0ah, "$"
text3 db 0dh, 0ah,"a/b:", 0dh, 0ah, "$"
quot db 0h
rem db 0h
counter db 0h
dane ENDS
; C:\ml /Fl /Zm /Zi /c lab3.asm
; E:\link /CODEVIEW lab3.obj
rozkazy SEGMENT 'CODE' use16 ;segment rozkazu
ASSUME cs:rozkazy, ds:dane
start:
mov ax, SEG dane
mov ds, ax
mov cl, 03h
mov ch, 0Ah
mov dx, offset text
mov ah, 09h
int 21h ; "input divisor"
mov ah, 01h
int 21h ; input into al
mov cl, al
sub cl, 30h ; move to cl and subtract 30h to get value instead of ascii
mov dx, offset text2
mov ah, 09h
int 21h ; "input dividend"
mov ah, 01h
int 21h
sub al, 30h ; input into al and get number instead of ascii
jmp divide
divide:
cbw
div cl ; convert al to ax and divide by cl
mov dl, ah
cbw ; convert al -> ax
push ax ; push ax to stack
mov al, dl ; move remainder from division to al
xor ah, ah
cbw
mul ch ; clear ah and al - > ax, multiply remainder times 10
inc counter ; increase counter by 1
cmp counter, 14h ; if the division was preformed 20 times, jump to show
jz show
jmp divide
show:
mov dx, offset text3
mov ah, 09h
int 21h ; "your number"
mov bx, sp
sub bx, 160 ; get stack pointer address and subtract by 8*20 (to get address of the number that is 20 positions down from sp)
jmp show2
show2:
mov dx, [bx] ; move value to dx from address that is stored in bx
add dl, 30h ; add 30h to get ascii
mov ah, 02h
int 21h ; write dl out
dec counter ; decrease counter
add bx, 8h ; move our memory pointer 8 up (to next number)
cmp counter, 0h
jz finish ; if counter = 0 jump to finish
jmp show2
finish:
mov ah, 4CH
int 21H
rozkazy ENDS
stosik SEGMENT stack
dw 128 dup(?)
stosik ENDS
END start
push ax
将 2 个字节存储到内存中,你这样做 20 次 = 40 个字节。我不明白你是如何设法找到 sub bx
.
的 160
堆栈也会向下增长,即如果在循环之前 sp
是 1234
,那么在第一个 push ax
之后它将被调整为 1232
(- 2), al
值就在 [1232]
和 ah
处 [1233]
.
所以你应该 add bx,19*2
计算第一个存储数字的地址,然后 sub bx,2
移动到下一个。
顺便说一句,在这种情况下,甚至不存储值,而是立即输出它们会更有效率,所以我猜你是在进行堆栈内存操作。
还可以使用一些调试器自己检查内存和地址,如果您在每个 push ax
之后标记 sp
,那么您的错误应该很明显,您将特定数字存储在哪里。 Microsoft DOS 中有某种 "cv.exe"(代码视图),或者您可以尝试搜索其他流行的 DOS 调试器,尽管其中大多数可能很难通过合法途径获得。
您也可以考虑使用一些现代工具,例如带有内置调试器的 DOS 仿真器(某些 dosbox 构建有它,或 BOCHS 等...),它们通常比 SW 调试器更强大 运行 在 DOS 中。
哦,现在我明白了……
subtract 20 digits * 8 bits from it
内存可以按字节寻址,而不是按位寻址,因此建议您可能需要调整 20(20 位数字 * 1 字节)。但是你做的是push ax
,存储的是16位,而不是8位(因为x86-16 CPU上没有push 8 bits
指令),16位是2个字节,所以需要20 * 2 = 40并且在相反的方向。
我正在编写一个 ASM 程序,将两个数字相除并计算小数点后 20 位。我的策略是通过长除法过程计算下一个数字并将它们压入堆栈。然后获取堆栈指针,从中减去 20 位 * 8 位并从该地址写入数字,然后将 8 添加到该地址,写入该数字等。但是当我尝试它时它只写出零。这些数字在堆栈上,因为我只尝试 "popping" 它们并且工作正常。我只需要它们以与它们被推入时相同的顺序弹出,而不是颠倒。
我的代码:
dane SEGMENT ;segment danych
text db 0dh, 0ah,"Give b (a/b)", 0dh, 0ah, "$"
text2 db 0dh, 0ah,"Give a (a/b)", 0dh, 0ah, "$"
text3 db 0dh, 0ah,"a/b:", 0dh, 0ah, "$"
quot db 0h
rem db 0h
counter db 0h
dane ENDS
; C:\ml /Fl /Zm /Zi /c lab3.asm
; E:\link /CODEVIEW lab3.obj
rozkazy SEGMENT 'CODE' use16 ;segment rozkazu
ASSUME cs:rozkazy, ds:dane
start:
mov ax, SEG dane
mov ds, ax
mov cl, 03h
mov ch, 0Ah
mov dx, offset text
mov ah, 09h
int 21h ; "input divisor"
mov ah, 01h
int 21h ; input into al
mov cl, al
sub cl, 30h ; move to cl and subtract 30h to get value instead of ascii
mov dx, offset text2
mov ah, 09h
int 21h ; "input dividend"
mov ah, 01h
int 21h
sub al, 30h ; input into al and get number instead of ascii
jmp divide
divide:
cbw
div cl ; convert al to ax and divide by cl
mov dl, ah
cbw ; convert al -> ax
push ax ; push ax to stack
mov al, dl ; move remainder from division to al
xor ah, ah
cbw
mul ch ; clear ah and al - > ax, multiply remainder times 10
inc counter ; increase counter by 1
cmp counter, 14h ; if the division was preformed 20 times, jump to show
jz show
jmp divide
show:
mov dx, offset text3
mov ah, 09h
int 21h ; "your number"
mov bx, sp
sub bx, 160 ; get stack pointer address and subtract by 8*20 (to get address of the number that is 20 positions down from sp)
jmp show2
show2:
mov dx, [bx] ; move value to dx from address that is stored in bx
add dl, 30h ; add 30h to get ascii
mov ah, 02h
int 21h ; write dl out
dec counter ; decrease counter
add bx, 8h ; move our memory pointer 8 up (to next number)
cmp counter, 0h
jz finish ; if counter = 0 jump to finish
jmp show2
finish:
mov ah, 4CH
int 21H
rozkazy ENDS
stosik SEGMENT stack
dw 128 dup(?)
stosik ENDS
END start
push ax
将 2 个字节存储到内存中,你这样做 20 次 = 40 个字节。我不明白你是如何设法找到 sub bx
.
堆栈也会向下增长,即如果在循环之前 sp
是 1234
,那么在第一个 push ax
之后它将被调整为 1232
(- 2), al
值就在 [1232]
和 ah
处 [1233]
.
所以你应该 add bx,19*2
计算第一个存储数字的地址,然后 sub bx,2
移动到下一个。
顺便说一句,在这种情况下,甚至不存储值,而是立即输出它们会更有效率,所以我猜你是在进行堆栈内存操作。
还可以使用一些调试器自己检查内存和地址,如果您在每个 push ax
之后标记 sp
,那么您的错误应该很明显,您将特定数字存储在哪里。 Microsoft DOS 中有某种 "cv.exe"(代码视图),或者您可以尝试搜索其他流行的 DOS 调试器,尽管其中大多数可能很难通过合法途径获得。
您也可以考虑使用一些现代工具,例如带有内置调试器的 DOS 仿真器(某些 dosbox 构建有它,或 BOCHS 等...),它们通常比 SW 调试器更强大 运行 在 DOS 中。
哦,现在我明白了……
subtract 20 digits * 8 bits from it
内存可以按字节寻址,而不是按位寻址,因此建议您可能需要调整 20(20 位数字 * 1 字节)。但是你做的是push ax
,存储的是16位,而不是8位(因为x86-16 CPU上没有push 8 bits
指令),16位是2个字节,所以需要20 * 2 = 40并且在相反的方向。