28X1: Method for writing modular code

#1
I've been meaning to write this up for a while, because it has worked well for me and might be useful. It's not as complicated as it might sound and I'll add a code template when I get time.

===================================================================

INTRODUCTION
---------------
The 28X1 has considerably more code-space than smaller picaxes, and more variables to use (b0 to b27), but it’s still easy to run out of variables when writing complex code, and it gets hard to debug and understand code when many symbols are assigned to the same underlying variables.

I’ve developed the following method of writing modular code that I’ve found very useful, especially when there is a lot of complex code. It’s a pretty simple, practical approach, and:

1. Makes coding and debugging easier because each module can be developed and tested independently.
2. Allows modules to be shared if people use the same approach.

OVERVIEW
----------
In this approach, the b0 to b27 variables are divided into two halves. One half is reserved for use in modules, the other half for ‘Global’ variables. This split is just a reasonable judgement of what might typically be needed.

The routines of the picaxe code are grouped into modules. Each module has it’s own symbol definitions relating to the module b-variables. When a subroutine in a module is called by another module it first ‘pushes’ a copy of the current module B variable values to a variable Stack. At the end of the sub it ‘pops’ these values back. The Stack is held in a section of the ScratchPad.

Some subroutines within a module might only be called from other subs in that module – in which case no pushing and popping is necessary.

A section of RAM is reserved for what I call Transfer Data, and this allows parameters to be passed to and from modules. This is common RAM shared by all modules (so it might be misleading to call it Parameter Data). To have separate RAM reserved for each module seemed a bit wasteful in practice, and common RAM seems to still work well.

Before a sub is called in another module, data will typically be poked to the Transfer Data area of RAM. Then any results peeked after the sub has returned.

CODE LAYOUT
--------------
GLOBAL CONSTANTS
GLOBAL VARIABLES
RAM CONSTANTS
- XFER VARIABLES
SCRATCHPAD CONSTANTS
- VARIABLE STACK
MODULE0 (Main)
MODULE1
MODULE2
etc
SYSTEM MODULE
- Push and Pop routines
- Interrupt routine (if required)

MODULE LAYOUT
----------------
LOCAL CONSTANTS
LOCAL VARIABLES
SUBS CALLED EXTERNALLY (Each sub starts with a call to PushVariables and ends with a call to PopVariables)
LOCAL SUBS (No need to call Push and pop routines ).

DESIGN TIPS
-------------
1. You might want to use the same names for variables across different modules, like ‘Counter’ or ‘Index’. Because we can’t have multiple definitions of the same name, give each module a number and append the number to any common symbol names. E.g use ‘Counter9’ in module 9.
2. Pushing and popping adds execution time, so it’s best to try to minimise calls between modules by careful choice of how the subs are grouped.
3. If you want to use the Scratchpad for other purposes then you won’t want to allow the variable stack to get too deep while code is executing – You can set the maximum stack level in the push routine , which detects stack overflow.
4. It is possible to make each subroutine a module in itself, but in practice it will probably be better to group up subroutines into modules.
 
Top