One of the challenges in writing assembly code is the level of detail required to accomplish even simple things. On smaller processors, like the 6502, the architecture tends to be quite limited - offering only a small set of instructions and registers.

Compared to writing code in a higher level language like BASIC, C, C++ or Java the difference can be quite daunting at first. Even simple things like printing results to a screen can be complicated (dependent on how you wish to represent the results) and everything needs to be broken up into quite tiny steps.

This is also one of the charms of writing code at this level, it is a very pure expression of what the processor really does. Nonetheless, when building complicated algorithms or larger programs this aspect of assembly code can cause difficulty

One of the ways of dealing with this issue is to prototype your algorithm(s) in a higher level language - meaning you write and test it in a higher level language first before creating an assembly version. If done properly, this tactic allows you to take an already working algorithm and merely convert it to assembly after you are happy with it.

Depending on your preference (and assembly skills), pretty much any language can be used. Of course, the more features of the chosen language are used, the harder it becomes to translate the resulting algorithm back to assembly.

My personal viewpoint in this is that a language like BASIC or C* is probably preferable to most others. The reasons being that both these languages have a relatively simple structure that is close to the overall structure of an assembly program and that both languages lack the more advanced data structures used in object oriented languages - which makes the translation easier**.

To show how this prototyping would work, I'll give a very simple example with some (hopefully) useful tips. We'll be translating the following BASIC code snippet into 6502 assembly:
X = 0
Y = 0
FOR Y = 0 TO 10
X = X + 1
Riveting stuff to be sure, but it will suffice to show the basic idea. Note that I assign each variable a starting value. This is not required in all languages, but doing so helps the conversion as assembly does not initialise anything to any known value unless explicitly done in code.

Translating this into assembly leads to the following snippet:
	 LDX #$00	; X = 0
LDY #$00 ; Y = 0
FORLOOP: INX ; X = X + 1
INY ; For Y = 0 to 10
CPY #$0b ; In BASIC a FOR loop includes the end value,
; so exit the loop at 11, not 10

The example above shows my method of doing this type of conversion.

Some noteworthy elements and tips:
  • The print_dec routine does not exist as such, creating this (or calling a comparable ROM function) is left as an exercise for the reader ;)
  • Note that the FOR ... NEXT loop is implemented as a post increment with a branch back. This is one of the easier ways to implement such loops in 6502 assembly and it also shows that converted code does not always follow the same order or structure as the original code.
  • For clarity, I tend to put a lot of comments in assembly code. Normally not quite as much as in this example, but a lot of comments nonetheless.
  • Also note that I add comments describing which part of the code I am converting, this makes debugging easier and makes it clear you're converting a piece of code from another language.
  • This example is not optimised, it is merely written to work. My view is that it is best to write something that works first and only afterwards add optimisations to make it faster or smaller.
  • I tend to write code like this by first making the loops and filling out the 'work' done in the loops later.

Other tips would be to write code for specific statements ahead of time, such as an IF ... THEN ... ELSE construct, various loops, a SWITCH ... CASE ... DEFAULT statement, etc. Possibly using macros to assist you. I also find it useful to write smaller chunks of code and test these smaller chunks before moving on to the next.

In conclusion, I feel that using the prototyping method I've outlined above can help make coding assembly simpler and may help in managing some of the more complex algorithms you may require.

*) I tend to use Blitzplus (a BASIC dialect based on Blitz Basic) myself, but like said, C will work just as well.
**) Obviously, it is not impossible to translate a fully object oriented approach to assembly, but it is (much) harder to do so than a simple function/procedural driven design.