<aside> 💡
Welcome to the first edition of a regular monthly column in STApplications. This is intended to be a space for ST programmers to raise issues, discuss techniques and get problems solved. As such, it will stand or fall on the reader response, so if you want to continue reading about programming on the ST, please write in.
</aside>
One of the major reasons for running a column like this is to encourage and advance ST programming by spreading ideas. The long-term survival of any computer depends on the production of quality software by an active community of developers. Since technical information about the ST is not easy to come by (partly owing to Atari's insistence on non-disclosure agreements for registered developers), many projects get delayed and/or abandoned when problems arise, simply because the problems have not been discussed and solutions published. Therefore, if you have hit a problem when programming, write in and describe it. Even better, if you encountered one and solved it, share your knowledge with other programmers to save them reinventing the wheel.
In order to keep the scope of the column wide, submissions will be accepted for any programming language, although I guess most will probably be in C, 68000 assembler or BASIC, as these are the most popular languages. As a general guide, the more technical and detailed a discussion is, the better. However, do not feel that anything is too simple to contribute. Items relating to the ST hardware and operating system will be especially welcome.
As well as problem-oriented discussions, I hope to include short reviews of specific aspects of ST programming. Once again, submissions are welcome, but should be kept to a moderate length. If you find that an area cannot be covered adequately in a short review, why not contact the editor with a view to submitting a full-length article?
Since this is the first column, there are no problems to discuss, and so the rest of the column will consist of a review of program initialization and memory management. This will probably be of most interest to assembly language programmers, as most compiled languages include a startup routine which takes care of initialization. However, the information here should be useful if you ever wanted to alter the code.
Leaving aside cartridge firmware, one can classify ST programs into four major groups which differ in (i) when they are run during boot-up, (ii) the system resources available to them, and (iii) the type of initialization code they require. In order of execution these are: boot sector programs, AUTO folder programs, desk accessories and finally 'normal' applications.
Most programmers will have developed applications which are designed to be run from the Desktop, either by double-clicking or with the Rainbow TOS autoboot feature. Such programs are loaded into the machine by TOS using the GEMDOS Pexec call. Immediately after loading, a program owns the entire TPA which is organized as shown in Figure 1. One of its first tasks is to return to the system any memory which is surplus to its requirements. If you do not do this, GEMDOS Malloc calls will most likely fail. This may cause problems for other programs such as desk accessories. Also rsrc_load may fail as it uses Malloc to get a buffer for the resource file. The memory restructuring is done using the GEMDOS Mshrink call. The parameters required for this call can be calculated from the basepage information (Figure 2). The basepage address is the second long word on the stack (i.e., sp+4).

Figure One: Layout of memory a) before and b) after the reorganisation of memory by Mshrink. The heap is an area of memory laid aside by many compiled languages for dynamic memory allocation.
Figure 2
The basepage structure. Fields which are not specified should be regarded as reserved.
Offset Name Function
$00 p_lotpa Pointer to TPA start
$04 p_hitpa Pointer to byte after end of TPA
$08 p_tbase Pointer to start of text segment (currently
always $100 bytes after basepage start)
$0C p_tlen Length of text segment
$10 p_dbase Pointer to start of data segment
$14 p_dlen Length of data segment
$18 p_bbase Pointer to start of BSS segment
$1C p_blen Length of BSS segment
$20 p_dta Pointer to program DTA (currently $80 bytes
after basepage start)
$24 p_parent Pointer to parent process basepage
$1C p_env Pointer to enviroment data
$80 p_tail Command tail data (up to $80 bytes)
Notice that the program will have to move its stack before calling Mshrink, otherwise the stack will be returned to the system! The program may then go on to use any of the system resources (GEM, Line A etc.) after appropriate initialization.
Programs are entered with a default DTA at offset $80 in their basepage. This overlies the command line arguments, so if you are going to use sfirst or fnext, either do command line processing first, or move the DTA. No other system calls use the DTA.
AUTO folder programs are executed after TOS is fully initialized, but before GEM is available. Therefore, they may use the GEMDOS, BIOS, XBIOS and Line A routines freely, but must not call the AES or VDI. Therefore, all AUTO folder programs are actually .TOS programs in spite of their PRG extensions. The operating system does a sfirst/fnext search for \AUTO\*.PRG on the boot drive (device number in _bootdev $446), calling Pexec in turn for each file found. Therefore, the order of execution is the order in which the files are entered in the AUTO directory, not that in which they are displayed on the Desktop.
Like normal applications, AUTO folder programs have a basepage address passed to them on the stack, and own the entire TPA. Strictly speaking, they should size their memory in the same way as a normal program in order to ensure compatibility with any future TOS behavior. However, most AUTO folder programs seem either to make a small alteration to the system (e.g., forcing a change to medium resolution) or to install resident code. In the first case, if the program does not use system functions, it is possible to simply have the program perform its task and Pterm. In the latter case, memory is given back to the system as part of the Ptermres call. AUTO folder programs should be careful if they install a VBL queue routine. When GEM is initialized it does not seem to check the queue properly for existing entries; it simply takes the first vector. Therefore, programs should check and use entries from the second onwards.
Desk accessories are rather different from most applications in that they are not treated as separate GEMDOS processes, but as part of GEM. This causes major complications in memory management. Accessories are loaded after AUTO folder programs, just before the Desktop is brought up. The accessory environment is also rather different from that of other programs. Most importantly, the stack pointer is not valid when the code is started. Therefore, the first job for an accessory is to create a new stack. Obviously, this must be done before any system calls. An easy way to handle this problem is to reserve (say) 1K of BSS and immediately on entry to the code, load the address of the end of this space into a7. If this is not done, a bus or address error will occur as soon as the stack is used. If the accessory has to access its basepage, the required address is in a0 when the accessory is started.
Memory management for desk accessories is rather complicated. GEM has presized the system memory to exactly the amount required before executing the accessory, so there is no need to call Mshrink. If the program does not need any more space than is reserved by its BSS, nothing need be done. However, if more memory is needed, your program may safely call Malloc, but this is best done before any AES calls.
This is because GEMDOS records the owner of each block of memory by stamping its header with an identifier. Blocks are tagged with a reference to the current active process. (This will never be the desk accessory itself, but either the Desktop or an application program.) When a process quits, all of its blocks are freed. An accessory will not know whether its memory block has been lost in this way. The trick is to get memory blocks while the active process is one that will never quit: the Desktop. Therefore, blocks allocated before the first AES call will be safe (any AES call is an opportunity for task switching by the system). If memory must be allocated dynamically after startup, the accessory should Malloc the block, use it, and then Free it without making any intervening AES calls. Of course, if the active process has kept all the system memory for itself (by not calling Mshrink), the accessory may not be able to Malloc its block successfully!