Modules
Modules are a collection of routines, with some modular data that have a
common purpose. As you have seen in the previous section about routines,
there are many reasons to create a routine. Modules provide a way of extending
this concept, and creating a black box set of routines to a particular 'concept'.
Usually the module is contained within one file. You CAN create modules
that span a number of files, but the protection that the assembler provides
against using the routines and data from another routine is gone***. It
then relies on the programmer to keep the interface to the module 'clean'.
The statement marked *** above is not necessarily true. You could create
two headers for each module. One header would be the modules private definition
file, and the other the modules public definition file. The private definition
file would be included within all the files that make up a particular module.
The public definition file would be included in all the other modules which
wanted to use the facilities offered by the other module. This would allow
the assembler to inhibit illegal cross modular references.
The are several parts of a module. Modular data (covered further down),
the public routines (that are accessed by the other modules) and the private
routines (that are only accessed by this modules routines).
Because defining the available (external) access from other routines (public
routines) can be a pain, you can generate a small include file with the
externs in so that all the public routines can be included easily.
Module Data
Local data is data that only exists whilst a routine is in existence. Such
data is typically stored in a dynamic storage area (for example on the stack)
or in registers.
Global data is data that can be accessed by the entire program. It is typically
stored in a5 global data (Mac 68K), BSS section (Mac PPC), or with the program
code (with dc.b) with external references to it.
There are problems with both these types of data. Local data does not exist
long enough to store some data needed - and even if it does - you quite
often need to have access from several related routines. Global data's problems
stem from several points - mainly its lack of 'security' - it can be changed
by any routine in the whole program, and at any time. Also it can be difficult
to change lots of references to a particular piece of global data if it
needs to be revised or expanded.
Modular data is data that is local to a module. It is not publicly defined
outside that module - and hence you cannot access it from anything but that
module. The general concept is that you COULD change it, but that would
be breaking the modular data. In this way even with assemblers that don't
enforce such label 'scope' rules, you can still use modular data. You must
just ensure you don't access another modules data.
A typical example of modular data is as follows. In an employee record program,
the accesses to the actual employee record data structure are all handled
by several public routines within one module. There are also private routines
for this module that are only used within the module. The actual data structure
is defined as modular data.
That way, the programmer(s) know that if there is a problem with the data
stored in the record (i.e. illegal data) or the data structure needs updating
(say for instance it needs changing from an array to a linked list) only
one module needs updating.
Implementing Modules in Fantasm
(Note: Public is an alias for Global in fantasm!)
Use the extern and public directives for routines that
are public. Don't for private routines!!!!
The best approaches to local data are to either use the stack to create
local data, or use registers. You can use Fantasm's abilities to rename
registers to make them clearer in use.
There are effectively two types of global data - preinitialised (at assembly
time - e.g. text strings) and uninitialised.
On the 68k, the globoff directive creates uninitialised global data,
accessed by referencing an a5 offset. On the PPC, uninitialised data is
created in the BSS section using the rs directives.
The dc directives creates preinitialised data. This is local to the
file - and to make it global requires the use of the extern and public
directives on the 68k, and the extern_data and public on the
PowerPC.
Again there exists two types of modular data - preinitialised and uninitialised.
Currently there is no specific way to create ASSEMBLER CROSS MODULE CHECKING
for uninitialised modular data, because the globoff and BSS rs
(PowerPC) directives are needed to be globally defined (the counters are
reset at the beginning of each assembler pass).
There are several things you can do:
Both of these are quite acceptable. It DOES NOT MATTER if the preinitialised
data you are using is changed before using it. It can contain garbage (although
like all these things, good garbage is probably zero - defensive programming).
We are thinking of putting some new directives in Fantasm to support this
type of data specifically. There might also be a work around - perhaps with
Macro's doing some of the leg work. The work around basically needs to allocate
global data where the label is private - hence protecting it from accidental
coding usage. Ideas welcome, else keep your eye out here. For the mean time
use the two methods as above.
Preinitialised module data can be created in the same way as per global
data. If you wish it to remain private in this file (module) you must obviously
not use extern/extern_data/public on it!
Remember: This data needs to be stored on disk as part of the code section
or data section of the application - so don't allocate massive amounts of
this type of data!! Generally, above 5K is excessive! You would probably
be better reading in a resource, or a data file, and then accessing via
a pointer.
BACK TO ASSEMBLY CODING STYLES