英文:
8086 Assembly - A simple recursion (number prefix) call-back problem
问题
你好,Assembly社区!
我目前是一名工程学生,尝试解决了一些我的家庭作业问题,大多数都很简单,但有一个问题困扰了我10个小时。
该问题要求我创建一个接收以十六进制格式表示的16位无符号数的例程,要使用栈,然后将该数字以十进制格式打印出来,使得每一行代表一个前缀,例如对于输入'B26Eh',我们应该得到:
- 45678
- 4567
- 456
- 45
- 4
程序必须实现递归,并且我们必须通过栈提供输入。
我编写了以下代码:
.model small
.data
.stack 100h
.code
START:
; 将屏幕数据设置到ES寄存器
MOV AX, 0B800h
MOV ES, AX
; 设置数据段
MOV AX, @data
MOV DS, AX
; 屏幕偏移
MOV CX, 0d
MOV BX, 340h
; 测试结果
MOV AX, 746FH
PUSH AX
CALL numPrefix
; 退出并打印两次运行结果
MOV AX, 4C00h
INT 21h
numPrefix PROC
; 保存寄存器
PUSH BP
PUSH DX
MOV BP, SP
MOV AX, [BP+6d]
; 基本条件
CMP AX, 0
JE baseCase
; 否则,将输入除以16d以获得商和余数
PUSH CX ; 保存打印地址
mov cx, 10 ; 除数
xor dx, dx ; 清除dx以存储商
div cx ; 将ax除以cx,商在ax中,余数在dx中
POP CX
; 递归调用numPrefix,传递商
push ax ; 将商推入栈中
call numPrefix
; 打印逻辑 #################################################################################
; 现在我们打印递归中每一行得到的结果
MOV DH, 2Eh
SUB BX, 0A0h
PUSH BX
PUSH CX
CMP CX, 0d
JE equalZero
printLoop:
; 对于递归中的每一行,打印相应的数字行
MOV SI, BX
MOV DI, [BX+0A0h]
PUSH AX
MOV AX, ES:[SI]
MOV ES:[DI], AX
POP AX
ADD BX, 1
loop printLoop
equalZero:
POP CX
; 添加新成员
ADD BX, 1
MOV ES:[BX], DX
POP BX
INC CX
; 打印逻辑 #################################################################################
; 完成并恢复寄存器
; 也是基本情况,我们只打印不再递归
baseCase:
pop DX
pop BP
ret 2
numPrefix ENDP
END START
我脑海中的逻辑相当简单,我将利用除以16h会得到新的AX(商),余数(DX)将被打印出来的事实。每次递归调用这个例程时,我都会使用“打印”函数来处理递归的每个级别,将前一行复制并将新的余数(DX)添加到新的行中。
但是代码不起作用,我尝试了在DOSBOX中进行调试数小时,每次我以为我搞清楚了,但最终调试器就会跳到内存中的随机位置。我已经调试了数小时了,希望能得到一些帮助。
谢谢!
编辑:看来我解决了一些问题,我认为递归跟踪回了正常位置,但似乎无法从递归回溯中获取DX(余数),希望能得到帮助!
最终编辑:问题解决了,谢谢大家的帮助!
英文:
Hello Assembly community!
Currently I'm an engineering student that tried solving a few of my homework questions, most of them were simply enough, but one question haunts me for 10 hours now.
The question asks that I create a routine that receives a 16bit unsigned number in HEX format Using the stack and print the number in decimal format such that each row represents each prefix, for example for input 'B26Eh' We should get:
- 45678
- 4567
- 456
- 45
- 4
The program must implement a recursion and we must provide the input through the stack.
I have written the following code:
.model small
.data
.stack 100h
.code
START:
; Setting screen data into ES register
MOV AX, 0B800h
MOV ES, AX
; Setting the data segment
MOV AX, @data
MOV DS, AX
; Screen offset
MOV CX, 0d
MOV BX, 340h
; Testing result
MOV AX, 746FH
PUSH AX
CALL numPrefix
; Exit and print both runs
MOV AX, 4C00h
INT 21h
numPrefix PROC
; Save registers
PUSH BP
PUSH DX
MOV BP, SP
MOV AX, [BP+6d]
; Base condition
CMP AX, 0
JE baseCase
; Else, divide the input by 16d to get the quotient and remainder
PUSH CX ; Save print address
mov cx, 10 ; Divisor
xor dx, dx ; Clear dx for the quotient
div cx ; Divide ax by cx, quotient in ax, remainder in dx
POP CX
; Call numPrefix recursively with the quotient
push ax ; Push the quotient onto the stack
call numPrefix
; PRINT LOGIC #################################################################################
; Now we print what we got for each row in the recursion
MOV DH, 2Eh
SUB BX, 0A0h
PUSH BX
PUSH CX
CMP CX, 0d
JE equalZero
printLoop:
; For each row in the recursion, print the appropriate row of numbers
MOV SI, BX
MOV DI, [BX+0A0h]
PUSH AX
MOV AX, ES:[SI]
MOV ES:[DI], AX
POP AX
ADD BX, 1
loop printLoop
equalZero:
POP CX
; Add new member
ADD BX, 1
MOV ES:[BX], DX
POP BX
INC CX
; PRINT LOGIC #################################################################################
; Finish and restore registers
; Also Base case where we only print and not do recursion again
baseCase:
pop DX
pop BP
ret 2
numPrefix ENDP
END START
The logic in my mind was quite simple, I will use the fact that dividing by 16h will give me the new AX (the quotient) and the remainder (DX) is to be printed.
Each time recursively I tried re-calling this routine and using the 'print' function for each level of the recursion I am copying the previous row and adding the new remainder (DX) to the new row.
The code won't work, I tried debugging it with DOSBOX for hours now, each time I think I figure it out but eventually the debugger just jumps to random places in the memory after I do the call-back of the recursion. I've been debugging it for hours now and I hope I can have some help.
Thank you!
EDIT: It seems I fixed some of the issues, I think the recursion traces back to it's normal place, but I can't seem to get back the DX (remainder) as I trace back from my recursion, help is appreciated!
FINAL EDIT: Solved, thanks everyone!
答案1
得分: 1
你显然在我写答案时就解决了它。干得好!为了不让它白费,这是我想出的内容。可能对比解决方案有用...
你的递归是正确的,但与屏幕的交互不正确。
例如:MOV DI, [BX+0A0h]
应该改为 lea DI, [bx - 160]
ORG 256
mov ax, 0B800h
mov es, ax
xor cx, cx
mov bx, 0340h
mov ax, 746Fh
push ax
call numPrefix
mov ax, 4C00h
int 21h
; ---------------------------
numPrefix:
push bp
push dx
mov bp, sp
mov ax, [bp+6]
test ax, ax
jz baseCase
mov di, 10
xor dx, dx
div di
push ax
call numPrefix
sub bx, 160 ; 上移 1 行 !!!
push bx
test cx, cx
jz equalZero
push ax
push cx
printLoop:
mov ax, [es:BX+160] ; 从低到高复制 !!!
mov [es:BX], ax
add bx, 2 ; 每个字符单元 2 个字节 !!!
loop printLoop
pop cx
pop ax
equalZero:
add dx, 2E30h ; 转换为文本并设置属性 !!!
mov [es:bx], dx
pop bx
inc cx
baseCase:
pop dx
pop bp
ret 2
英文:
You apparently solved it while I was writing an answer. Good for you! So it doesn't go to waste, here is what I came up with. Probably useful to compare solutions...
Your recursion was fine, but the interaction with the screen wasn't.
eg. MOV DI, [BX+0A0h]
would have to be lea DI, [bx - 160]
ORG 256
mov ax, 0B800h
mov es, ax
xor cx, cx
mov bx, 0340h
mov ax, 746Fh
push ax
call numPrefix
mov ax, 4C00h
int 21h
; ---------------------------
numPrefix:
push bp
push dx
mov bp, sp
mov ax, [bp+6]
test ax, ax
jz baseCase
mov di, 10
xor dx, dx
div di
push ax
call numPrefix
sub bx, 160 ; 1 row up !!!
push bx
test cx, cx
jz equalZero
push ax
push cx
printLoop:
mov ax, [es:BX+160] ; copy from lower to higher !!!
mov [es:BX], ax
add bx, 2 ; 2 bytes per charactercell !!!
loop printLoop
pop cx
pop ax
equalZero:
add dx, 2E30h ; Convert to text plus set attribute !!!
mov [es:bx], dx
pop bx
inc cx
baseCase:
pop dx
pop bp
ret 2
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论