1

I'm trying to do a fibonnachi sequence in debug x86-16 dosbox assembler but im haveing trouble, i keep getting this weird printout:

enter image description here

I was trying to break it down piece by piece but here is what i have so far

mov cx, 15
mov al, 01
mov bl, 00
cmp cl, 1
je  010B     ;next line with mov ah, 2
mov ah, 2
int 21
inc cl
cmp cl,2
je  0115     ;next line with mov ah, 2
mov ah, 2
int 21
inc cl
add al, bl
mov bl, al
mov cl, bl
mov ah,2
int 21
loop (inc cl line)
rcx 
4A
w
q

Im not sure if it is right but it is supposed to print out the first 20 numbers in the Fibonacci sequence, please help if you can

EDIT: i got it to print 01 by using

mov cx, 15
dec cx
mov al, 30
mov bl, 31
mov cl, 31
cmp cl, 31
je 010F
mov dl, al
mov ah, 2
int 21
dec cx
inc cl
cmp cl, 32
je 011c
mov dl, bl
mov ah, 2
dec cx
inc cl
int 21
int 20

now i just need to have ax=bl+al, al=bl, and bl=ax, any idea on how to do that?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Does this assignment require the result to be output to the console window? If so, then you need to make a function to convert a binary number to a string in order to display the string. – rcgldr Sep 16 '17 at 06:57
  • I don't see how "x86-16 Assembly" is a better title than "Fibonacci x86-16 Assembly". Neither of them describe the actual problem you're having, just the context you're having it in, but if anything you should make the title more specific, not less. – Peter Cordes Sep 19 '17 at 02:36

2 Answers2

4

INT 21h, AH = 02h is supposed to output one byte to standard output, where that byte is to be passed in the DL register. Your code never even initializes DL so it isn't surprising that it outputs garbage.

You have several other problems too. If you want readable output you have to do binary-to-decimal conversion and then convert to ASCII; your code doesn't seem to even be trying to do that. Also, you are doing all your arithmetic in the 8-bit AL, BL registers, but the 20th Fibonacci number is larger than 8 bits, so at some point it will overflow and you won't get the right answers.

Finally, if you want to write a real program in assembly language, then DEBUG is an incredibly inconvenient way to proceed. It hasn't evolved in almost 40 years. Get a real text editor and a real assembler, as well as a real debugger.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • well this is what i type to check it out mov dl,1 mov ah, 2 int 21 and it printed out a smile face, i dont know this language well – johnny rand Sep 14 '17 at 05:11
  • I am using ASCII, 15 = 21, 01=1, so i am using ASCII, and dosbox will not let me use eax or any of those other bigger registers – johnny rand Sep 14 '17 at 05:16
  • @johnnyrand: pretty sure DOSBOX emulates a 386-compatible CPU, unless you tell it not to. Maybe you're using an assembler that won't assemble 32-bit operand size overrides. But anyway, Fib(20) fits in a 16-bit register, so you should just use `add ax,dx` / `add dx,ax`. Single-step your code with a debugger. – Peter Cordes Sep 14 '17 at 05:23
  • @johnnyrand: That's exactly what you should expect. You are outputting character 01h and that displays as a smiley face. If you want to output the character `1`, it's 31h. See [ASCII table](http://www.asciitable.com/). – Nate Eldredge Sep 14 '17 at 05:25
  • 1
    @PeterCordes: It's not DOSBOX specifically, it's that the assembler is the one from the DEBUG command (of whatever DOS version is running in the emulator), which AFAIK has never supported 32-bit instructions. – Nate Eldredge Sep 14 '17 at 05:26
  • 1
    I wish I could use something elss, but this is a homework assignment that my professor said to use – johnny rand Sep 14 '17 at 11:05
  • @PeterCordes - debug is a 16 bit program. If it runs at all, then it is running in 16 bit mode. It won't run in a 64 bit Windows console, but it can be run within a virtual PC with MSDOS installed. – rcgldr Sep 15 '17 at 00:34
  • 1
    @rcgldr: `add eax, edx` in 16-bit mode is encodeable with a `66` operand-size prefix. So that wasn't inherently an obstacle, it's just a software limitation as Nate says. Anyway, the OP's problem is using 8-bit registers when they should be using 16-bit. 32-bit isn't needed for Fib(20), and if it was you could do it with adc for extended precision. (related: https://codegolf.stackexchange.com/questions/133618/extreme-fibonacci/135618#135618: 105 bytes of x86-32 machine code for a complete Linux program to print the first 1000 decimal digits of `Fib(10^9)`, runs in ~1 minute.) – Peter Cordes Sep 15 '17 at 00:41
  • @johnnyrand: you could develop in a nicer environment and then copy your code into `debug.exe`, if it's not a nice debugger for single-stepping and interactive use. – Peter Cordes Sep 15 '17 at 00:43
  • @PeterCordes - I wonder how many people have a copy of the old Microsoft toolset: masm (ml.exe), codeview (dos source level debugger), programmer's workbench (dos IDE), ... ? For those that do, then a .COM program can be built using "tiny" model. I don't recall if Borland's old toolset included support for assembler. – rcgldr Sep 15 '17 at 01:48
  • @rcgldr: `.com` doesn't have any header bytes or anything, so you can build one with NASM's flat binary output, with the right `ORG` directive, IIRC. Personally, I don't see the point of 16-bit code for anything but bootloaders these days, except as a way of understanding how x86 evolved into its current state (aka mess), especially with segment registers. There is plenty of interesting stuff to do with 32/64-bit asm. – Peter Cordes Sep 15 '17 at 01:54
  • @PeterCordes - outside of a classroom, I don't see much need for 16 bit code either. I still have my old Microsoft toolset. I rarely use it, other than for questions like this one. I also have some old dos games that I run on either dosbox or virtual PC with old copies of msdos 6.22 and even Win 3.11. – rcgldr Sep 15 '17 at 02:00
  • @rcgldr: 16-bit code is harder to learn than 32-bit or 64-bit user-space. Especially if you only teach a simple subset of instructions to keep it simple, like don't get into `bts`. You can teach segmentation later; it's a huge complication compared to simple flat address space. IDK if beginners find the partial-register stuff confusing, but other than `setcc`, with 32-bit code you can mostly not use partial registers except for storing chars with `mov [mem], al`. (load with `movzx`). In 16-bit code, many system-call ABIs use partial registers so you have to learn that right away, too. – Peter Cordes Sep 15 '17 at 02:15
  • is debug still available in windows 10? – thang Sep 18 '17 at 23:43
1

now i just need to have ax=bl+al, al=bl, and bl=ax, any idea on how to do that?

For al=bl and bl=al, you can use the exchange instruction:

        xchg    al,bl

except that you need to use 16 bit registers in order to go up to fib(24) (46368), so that would be:

        add     ax,bx
        xchg    ax,bx

Optionally, you could do the xchg first.

        xchg    ax,bx
        add     ax,bx

You'll need to use a register other than ax, since it will be needed to convert binary to decimal and for the int 21 calls.

In case you're not already doing this, you can use debug.com as a crude assembler by redirecting its input to read it's commands from a text file. The commands will enter instructions and data, then use "n" to give a name of the program to write, "rcx" to set cx to the number of bytes to write, then "w" command to write the program. "q" exits debug.

This allows you to edit the text file until you get the program to work, as opposed to entering commands directly with debug. Here is an example input file for Fibonacci program named fib16.in:

a100
sub  sp,+10
mov  bp,sp
mov  byte ptr [bp+05],0d
mov  byte ptr [bp+06],0a
mov  byte ptr [bp+07],24
mov  di,ffff
mov  si,0001
mov  cx,0019
mov  bx,000a
xchg si,di
add  si,di
mov  bp,sp
add  bp,+05
mov  ax,si
dec  bp
xor  dx,dx
div  bx
or   dl,30
mov  [bp+00],dl
cmp  bp,sp
jnz  0128
mov  ah,09
mov  dx,sp
int  21
loop 011d
add  sp,+10
mov  ax,4c00
int  21

nfib16.com
rcx
47
w
q

To "assemble" this file enter the command:

debug <fib16.in

This will create a program called fib16.com, which you can then run with or without debug.

Here is a regular assembly version of the same program:

;       Fibonacci
        .model  tiny,c
        .code
        org     0100h
main    proc    far
        sub     sp,16                   ;allocate space for string
        mov     bp,sp
        mov     byte ptr 5[bp],00dh     ;bp[5] = 00d,00a,'$'
        mov     byte ptr 6[bp],00ah
        mov     byte ptr 7[bp],024h
        mov     di,0ffffh               ;fib(-2)
        mov     si,00001h               ;fib(-1)
        mov     cx,25                   ;loop: fib(0) to fib(24)
        mov     bx,10                   ;used to convert to string
main0:  xchg    si,di                   ;fib step
        add     si,di
        mov     bp,sp                   ;display si
        add     bp,5
        mov     ax,si
main1:  dec     bp
        xor     dx,dx
        div     bx
        or      dl,030h
        mov     [bp],dl
        cmp     bp,sp
        jne     main1
        mov     ah,009h
        mov     dx,sp
        int     21h
        loop    main0                   ;loop till done
        add     sp,16                   ;restore sp
        mov     ax,04c00h               ;exit
        int     21h
main    endp
        end     main
rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • 1
    The OP's code appeared to have numeric branch destinations. Is there no way to use labels in `debug`? If not, that's a horrible way to teach assembly, since you have to go and fix your branch offsets every time you add or remove an instruction! – Peter Cordes Sep 15 '17 at 06:05
  • I *think* the OP was already using input from a file. Upvoted your answer for explaining the apparent trailing garbage after the `loop` instruction in the OP's first code dump. – Peter Cordes Sep 15 '17 at 06:21
  • If this problem has caught your interest, then go nuts and post some interesting code. I'd assume the OP has moved on, and wouldn't bother trying to help them unless they respond. The OP's code has so many bugs that there's no single question you can even answer. (`inc cl` followed by `mov cl, bl`, and then `loop` looks like nonsense, and is at least two separate bugs (clobbering cx for `loop`, and clobbering the `inc cl` result without using it)...) – Peter Cordes Sep 16 '17 at 07:16
  • 1
    @PeterCordes - I updated my answer. The Fibonacci step is just two instructions (xchg, add). The rest of the code is to convert to a decimal string and display it. I used the stack for the decimal string. Uses all the registers, and doesn't need any memory based variables (except the string). At least the old 16 bit Microsoft tool set still works. – rcgldr Sep 16 '17 at 08:15
  • Nice. I might have used more meaningful label names than `main0` and `main1`, and maybe left a blank line between blocks. Also, probably `mov cx, 25` is easier to read than `mov cx, 0019h` since we're thinking about the count as a decimal number. Also, `push 0240dH' and so on before you `sub sp,16` is more efficient way to get string data onto the stack. If you needed another reg, you could "cheat" and `cmp si, Fib(24)` or something as the loop condition instead of a counter in `cx`. Or detect carry, since Fib(25) is the first one not to fit in 16 bits. – Peter Cordes Sep 16 '17 at 08:38
  • Wait, `debug` can't use decimal constants?? I guess 40-year-old software wasn't very user-friendly. You're just using `loop` because the OP was doing so, right? It's not a useful idiom to learn unless you're targeting a real 8086, because [`loop` is slow](https://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently) (except on AMD Bulldozer-family). If I was teaching x86, I wouldn't even mention it, or `aam` or `xlatb`. They exist, but nothing you can't do using the important instructions you have to learn anyway. – Peter Cordes Sep 16 '17 at 09:45
  • 8086 has cmp/jcc or dec cx/jnz. And that makes the usage of `cx` obvious; modifying `cx` inside a loop is a common beginner error which I think would happen less if people didn't insist on using an obscure instruction like `loop` to optimize for code size instead of just making loops the general-case way with jcc. (`loop` is one of my pet peeves. I know it was a performance win on real 8086 hardware, but it makes no sense to teach it in 2017.) Thanks for the heads up that `push imm16` didn't exist until later, though. – Peter Cordes Sep 16 '17 at 13:25