Variables

Variables come in several flavors.

Global variables

Global variables are variables that can be reached from any point in the program. Since the 6502 has no memory protection, these are easy to declare. Take some random chunk of unused memory and declare it to be the global variables area. All reasonable assemblers have commands that let you give a symbolic name to a memory location—you can use this to give your globals names.

Local variables

All modern languages have some concept of "local variables", which are data values unique to that invocation of that procedure. In modern architecures, this data is stored into and read directly off of the stack. The 6502 doesn't really let you do this cleanly; I'll discuss ways of handling it in a later essay. If you're implementing a system from scratch, you can design your memory model to not require such extreme measures. There are three basic techniques.

Treat local variables like registers

This means that any memory location you use, you save on the stack and restore afterwards. This can really eat up stack space, and it's really slow, it's often pointless, and it has a tendency to overflow the stack. I can't recommend it. But it does let you do recursion right, if you don't need to save much memory and you aren't recursing very deep.

Procedure-based memory allocation

With this technique, you give each procedure its own little chunk of memory for use with its data. All the variables are still, technically, globals; a routine could interfere with another's, but the discipline of "only mess with real globals, and your own locals" is very, very easy to maintain.

This has many advantages. It's very fast, both to write and to run, because loading a variable is an Absolute or Zero Page instruction. Also, any procedure may call any other procedure, as long as it doesn't wind up calling itself at some point.

It has two major disadvantages. First, if many routines need a lot of space, it can consume more memory than it should. Also, this technique can require significant assembler support—you must ensure that no procedure's local variables are defined in the same place as any other procedure, and it essentially requires a full symbolic linker to do right. Ophis includes commands for memory segmentation simulation that automate most of this task, and make writing general libraries feasible.

Partition-based memory allocation

It's not really necessary that no procedure overwrite memory used by any other procedure. It's only required that procedures don't write on the memory that their callers use. Suppose that your program is organized into a bunch of procedures, and each fall into one of three sets:

  • Procedures in set A don't call anyone.

  • Procedures in set B only call procedures in set A.

  • Procedures in set C only call procedures in sets A or B.

Now, each set can be given its own chunk of memory, and we can be absolutely sure that no procedures overwrite each other. Even if every procedure in set C uses the same memory location, they'll never step on each other, because there's no way to get to any other routine in set C from any routine in set C.

This has the same time efficiencies as procedure-based memory allocation, and, given a thoughtful design aimed at using this technique, also can use significantly less memory at run time. It's also requires much less assembler support, as addresses for variables may be assigned by hand without having to worry about those addresses already being used. However, it does impose a very tight discipline on the design of the overall system, so you'll have to do a lot more work before you start actually writing code.

Constants

Constants are "variables" that don't change. If you know that the value you're using is not going to change, you should fold it into the code, either as an Immediate operand wherever it's used, or (if it's more complicated than that) as .byte commands in between the procedures. This is especially important for ROM-based systems such as the NES; the NES has very little RAM available, so constants should be kept in the more plentiful ROM wherever possible.