recursionassemblyx86-16dosbox

8086 Assembly - A simple recursion (number prefix) call-back problem


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:

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!


Solution

  • 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