I am trying to build a Fibonacci sequence in a 6502 assembler. It needs at least one add function, a least one branch function, and at least one compare function. I know how to add and store integers, but I am confused by branch and compare functions.
Fibonnacci sequence in 6502 assembler
163 Views Asked by Liam Knipper AtThere are 2 best solutions below
On
I assume you are limited to using the instructions mentioned in the table. So you have CPX and you have BNE.
CPX compares the content of the X register with its operand. It does this by subtracting the operand from X and then setting some flags accordingly.
The 6502 has a status register containing a number of flags i.e. one bit values which represent "true" or "false". The flags are:
- N: "negative" is 1 if the result of the operation is negative in a 2's complement sense. e.g. if X contains
$01and you doCPX #$03the result would be$fewhich is -2 in 2's completement and theNflag will be set. - Z: "zero" is 1 if the result of the operation is 0, so
CPX #$01would setZifXcontains 1, or clearZifXcontains any other value. - C: "Carry" this can be a bit confusing, but in the context of a compare like
CPXit will be set if X is greater than the operand (interpreting both as unsigned).CPX #1will setCfor any value inXexcept 0 or 1.
There are several other flags, but we can ignore them because they are unaffected by CPX.
The branches in the 6502 work by inspecting one of the flags and then performing the jump, or not performing the jump depending on its value. There are two branches associated with each flag, one to jump if the flag is set and one to jump if the flag is clear.
For the C flag we have:
BCSjump if the carry flag is setBCCjump if the carry flag is clear
For the N flag we have:
BMIjump if the negative flag is setBPLjump if the negative flag is clear
The "MI" stands for "minus" and the "PL" stands for "plus"
For the Z flag, we have:
BEQjump if the zero flag is setBNEjump if the zero flag is clear
"EQ" means "equal to zero" and "NE" means "not equal to zero". These two opcodes could have been BZS and BZC respectively.
So, restricting yourself to the instructions in your list, If you have a loop counter at address loopCounter and the number of times you want to loop at address maxCount you could implement your loop as follows.
lda #0
sta loopCounter
loop:
; Do all the stuff you want to do for an iteration
inc loopCounter
ldx loopCounter
cpx maxCount ; sets Z if x and maxCount contain the same number
bne loop ; branches if Z not set i.e. x != maxCount
Note that the above always executes the loop code at least once and setting maxCount to zero will cause the loop to execute 256 times.
If you have the full 6502 instruction set you can make the above loop much more efficient. Even with just the DEX instruction (decrement X) you can store the count in X and count downwards. DEX is much faster than INC and DEX also affects the Z flag, so you don't need the CPX.
Addendum:
Not relevant to the question but I can't resist this, but the 14th Fibonacci number is 377 which doesn't fit in eight bits. If you want a really fast way to calculate any Fibonacci number that does fit in 8 bits, you can just do a lookup.
calculate8bitFibo:
; On entry X contains the zero based index of the number we want
; on exit A contains the Fibonacci number
; It is the caller's responsibility to make sure the index is in range
lda fiboTable,x
rts
fiboTable:
.db 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 237

In C code we might use a structured statement, here a while loop:
whereas using what can be called if-goto-label, the same (still in C) :
So, hopefully you see that these two constructions are equivalent and identical and will thus run the same, even though the latter is a bit more verbose. Both will run the same loop body for the same number of iterations.
The latter form, however, is much closer to assembly language, which also uses if-goto-label.
Key to assembly, then, is how the C-statement
if ( count != 0 ) goto Loop1;is performed. The issue with an if-goto-label statement in C is that there are generally too many operands for the processor to work with in one machine code instruction (here, those operands arecount,!=,0,Loop1and we can imagine each of those operands, in the general case, will need to vary.)So, the solution in many instruction sets is to split the if-goto-label construct into two instructions by connecting them using condition codes. Here, the first is would be a compare of
countand0that sets the condition codes, and the second is a branch using condition!=and label targetLoop1that reads the condition codes.These two instructions communicate via the condition codes, but you can read them as performing the if-goto-label construct via a two instruction sequence (here an extra instruction to clear the
Xregister for the latercpx):the above is then the assembly pseudo-code translation for the C-based if-goto-label construct
if ( count != 0 ) goto Loop1;.Each processor's operation and assembly language varies a bit, so one general idea that works well is to: