Scor­pio News

  

July–September 1988 – Volume 2. Issue 3.

Page 13 of 39

the main program sections must interact. The simplest approach in the long run is to relocate this code to the top of the TPA on loading and move the BDOS vector (which is used to define RAMTOP) to below it. Because the C compiler I used for the PCB package does not provide facilities for transferring global data from one program to another, I also put the two arrays on which the program works above the BDOS vector. The machine code includes routines to find the arrays and the C code then addresses them using pointer type variables. This approach also means that a computer with more RAM actually can hold more data rather than just having more wasted space. Unfortunately it is not nearly as easy in languages other than C or assembler.

An incidental note for users of HiSoft C. I use this version and as I stated above it does not directly provide for global variables to remain between programs. My solution in the PCB program works very well but it would not be suitable for one of my forthcoming projects. Fortunately, I have since discovered a neat little trick. HiSoft C usually places all static variables at the top of the TPA as found by the compiler, but this can be changed using the #data directive as described in the manual. What the manual does not say is that it is possible to have two or more #data directives in the source file. Variables always occupy the data area defined by the last #data before their declaration and, providing none of the areas overlap (and that there were no variables declared before the first #data), the program will compile and run correctly. However, only the last data area defined will be automatically filled with zero bytes when the program is run so all the other variables will be retained (providing they are defined in the same order in all programs). Note that the last data area should be the highest, otherwise the stack checking will not work properly.

The task of actually interfacing the high level code with the (relocated) machine code can also be tricky. My approach in C, which is totally portable and really quite neat, was to define a data type “func_ptr_ptr” as

typedef char * (* * func_ptr_ptr)();

This type code comes out as a pointer to (an array of) pointers to functions which return a pointer to character. I then defined a variable of this type which was loaded (indirectly) from the BDOS vector. Since the machine code creates a table of function addresses with a pointer just after the new BDOS vector, it is now possible to call these functions directly.

static func_ptr_ptr global_function;
global function = gbase(); –
(*global_function[ GET_DATA ])( &pads, &padpos, &tracks, &trackpos );

Page 13 of 39