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!)


ROUTINES

Use the extern and public directives for routines that are public. Don't for private routines!!!!


LOCAL DATA

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.


GLOBAL DATA

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.


MODULE DATA


Again there exists two types of modular data - preinitialised and uninitialised.

UNINITIALISED MODULE DATA

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

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