8086汇编 – 一个简单的递归(数字前缀)回调问题

huangapple go评论47阅读模式
英文:

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

huangapple
  • 本文由 发表于 2023年5月29日 07:12:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76353935.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定