Search code examples
assemblydosx86-16

Simple fibonacci printer in 8086 assemlby


I've been starting to learn assembly a few days ago and I'm trying to make a program to print the fibonacci series for up to 5 characters, but my code prints out weird characters

I thought it's because of the ASCII conversion system, but even when I add the value 48 to the number it's still not correct.

.model small 
.data
  lastFib DB 0
.code
  main PROC
    mov cx,5
    mov dl,48
  loopy: 
    add dl,lastFib 
    mov ah,2h          
    int 21h
    mov lastFib,dl   
    loop loopy 
  ENDP
end main

Solution

  • but my code prints out weird characters

    Adding 48 is only needed to output the (small) number as a character. You mustn't allow this addition of 48 to tamper with your calculations of the fibonacci numbers. In below code I add 48 just before calling DOS, and immediately after, I take the addition back.

    Currently your code does not calculate any fibonacci number at all. The basic scheme would be:

    xchg dl, lastFib   ; Exchange current with previous
    add  dl, lastFib   ; Add previous to current
    

    There are 6 single digit fibonacci numbers: 1, 1, 2, 3, 5, 8.
    By outputting before calculating the next fibonacci number, the below code manages to print all 6 numbers in one loop. A 7th number (13) is calculated but never displayed.

    .model small 
    .data
      lastFib DB 0       ;previous
    .code
      main PROC
        mov  cx, 6
        mov  dl, 1       ;current
      loopy:
        add  dl, 48      ;make character
        mov  ah, 02h
        int  21h
        sub  dl, 48      ;take back
        xchg dl, lastFib
        add  dl, lastFib
        loop loopy
      ENDP
    end main
    

    Why don't we optimize the code a bit?

    • With plenty registers available, there's no reason to keep that lastFib variable in memory!
    • We could avoid the slow loop instruction as well as the costly xchg with memory.
    • Selecting a register other than DL for the current fibonacci number will shave off the extra 'take back' instruction.

    None of these changes will speed up this code because of the DOS api call involved. Nonetheless there're all good optimizations for when there's no such system call present.

    .model small 
    .code
      main PROC
        xor  cx, cx      ; Previous
        mov  bx, 1       ; Current
      loopy:
        lea  dx, [bx+48] ; Make character in DL
        mov  ah, 02h     ; DOS.PrintChar
        int  21h
        xchg bx, cx
        add  bx, cx
        cmp  bx, 10
        jb   loopy
      ENDP
    end main
    

    This time the loop is only continued for as long as the number in BX remains single digit.