The Complete STOS Reference

 pre-release 0.2 Edited By Dr Phibes

Writing STOS Extentions

part 2 of 3; By Martin Cubitt for STOSSER disczine

Part 1 | Part 3
In the last part of this series I looked at writing the interpreter version of an extension. Now we turn to the compiler extension. I must warn you that compared to the compiler extension the interpreter extension was EASY!.

The main routines used in your interpreter version can also be used in the compiled version but the header is very different.

The best thing to do is copy the interpreter source to the compiler sourceie copy EGINT.S to EGCMP.S. Then load EGCMP.S on your assembler and delete the entire header section. You may change the comments at the top to suit the compiler version. As in the last part, I have copied the actual source in and will break it down for you.

Start off with the usual introduction...

Source name: EGCMP.S
Object name: EG.ECW
Author: Martin Cubitt
Date: 15th Oct 1993
Description: Example STOS Compiler extension Contains 1 new command and 2 new functions  (remember that a function returns a value)

eg

- this command displays the command list of the EG extension. I think  all new extensions should have a similar command as an on-line reference to commands available.

 A=range(A,B,C)

- a function which returns a value based on A in the range B to C. If A is less than B then A will become the value of B. If A is greater than C then A will become the value of C. If the value of A >=B and <=C then it will be unchanged.

 A=ndrv

- this function returns the number drives attached to your system (and are available or turned on). If you have the internal, one external and a RAM disk the value will be 2 because the internal drive is assumed anyway.
The following variables are set up for use in the parameter list. I for integer, F floating point (or real), S for string and C for comma to separate parameters.

Compiler header

The compiler header starts with offsets to the parameter table, the initialisation routine and the first library routine. In the compiler extension the command routine is called a library.

 Parameter list offsets

START:
dc.l PARM-START
dc.l INIT-START
dc.l LIB1-START
A library catalog containing word values of the lengths of the library routines is next.

 Library catalog containing length of each library routine

CATALOG:
dc.w LIB2-LIB1
dc.w LIB3-LIB2
dc.w LIB4-LIB3
dc.w ENDPGM-LIB4
The parameter list starts with the number of library routines present, including dummy libraries. The first number is the number of libraries and the second is the number of commands. Presumably these may not actually be the same but I am afraid it is beyond me.

 Parameter list for each library routine, Number of libraries (including dummies)

PARM:
dc.w 4,4
The actual parameter list table follows. This holds the offsets to the parameter lists. A good naming convention of the parameter list names is to simply place a 'P' in front of what the command name label is.

Offsets to parameter lists

dc.w PEG-PARM
dc.w PRANGE-PARM
dc.w PDUMMY-PARM
dc.w PNDRV-PARM
The parameter list itself is next. This holds information about parameters coming in and being passed back for each command. The first byte, if present, reflects the value to be passed back. Nothing would mean no value is returned whereas S would mean a string value is returned. I understand that a 0 must be placed here even if it is a command but it is not necessary in my experience.

If parameter list for a command is terminated with 1,1,0. However, if you want to use more than one parameter list for a command (such as the ABS(n) function which can accept integer or floating point numbers) you simply end the first one with a single 1 and end the second t`list with 1,1,0.
In between the returned value and termination flag you put and parameters which may be passed to the command. This is explained below.

Parameter list

EG command uses NO parameters so just use end marker of 1,1,0
PEG: dc.b 1,1,0
The range function is Z=range(A,B,C). The parameter list for this is I,I,C,I,C,I,1,1,0. The first I is the returned value (Z). The second I is for the first parameter (A). The C shows that there are more parameters. The third I is for B and the fourth is for C. The 1,1,0 on the end is a termination code.

 RANGE function returns 1 integer (1st I) and then A,B,C

PRANGE:
 dc.b I,I,C,I,C,I,1,1,0

Dummy parameter list needs no parameter defined

PDUMMY:
 dc.b 1,1,0

 NDRV function returns just one integer parameter

PNDRV:
dc.b I,1,1,0
even
The routine must now be initialised. A simple jump to the cold start routine will suffice.

 Initialise the routine

INIT:
 bra COLDSTART
The cold start routine loads the address of the end of the extension into register a2.

 Actual cold start routine

COLDSTART:
 lea END(pc),a2
 A return (rts) instruction will do for this extension.
END:
 rts
That is the header completed, now down to the library routines themselves. These must be completely independent of position to each other. This is because the compiler only uses the library routines used in the BASIC program.

Each library routine must have a word declared at the start. This apparently is a kind of "I will not call other library routines" promise! The routine follows. Parameters are passed via the stack, reference by register a6. Data register d0 contains the parameter list being used but in this example each command has only one parameter list.

You must be careful when using data or address registers as other interrupt driven commands (or STOS itself) sometimes use them. The best thing to do is to save the lot and the restore them later.
 The routines end with a simple rts.

 eg command

EG:
LIB1:
dc.w 0
movem.l a0-a6,-(a7)
lea EGINFO(pc),a0
move.w #1,d7
trap #3
movem.l (a7)+,a0-a6
rts
Text for eg command. This has been moved from its position at the end of the program to be included within this library. If this is not done the text would not be used and incorrect data displayed.
EGINFO:
dc.b 10,13," EG (Example) extension by M.Cubitt 1993 "
dc.b 10,13,"eg................: Information"
dc.b 10,13,"=range(A,B,C).....: Make A in range B-C"
dc.b 10,13,"=ndrv.............: No. of drives" 
dc.b 10,13,0
even

 Range function

RANGE:
LIB2:
 dc.w 0
 Pull parameters off the stack in reverse order (last first).
move.l (a6)+,d0 ; C
move.l (a6)+,d1 ; B
move.l (a6)+,d2 ; A
cmp.l d1,d2
blt.s TOO_LOW ; A<B so A=B
cmp.l d2,d0
bge.s OKAY ; Leave A as is
move.w d0,d2 ; C<A so A=C
bra.s OKAY
TOO_LOW:
move.w d1,d2
OKAY:
Add the value to the stack in order to return it as a parameter.
move.l d2,-(a6) ; return parm
rts
Dummy libraries must still be defined.

 Dummy

LIB3:
dc.w 0

 Number of drives function

NDRV:

LIB4:
dc.w 0
moveq.l #0,d0
move.w ($4a6),d0
move.l d0,-(a6) ; return parm
rts
Mark the end of extension.
ENDPGM:
dc.w 0
Apparently when returning string parameters you should use the ASK routine and pass it data register d3 as a longword value containing the length of the string. Ie.
ASK equ 70
jsr ASK
This does not seem to work! If anybody can tell me more about using string in STOS, returning them, I will be very happy and thankful!
There you have it. The compiler extension. This was quite a simple one but they can get REALLY complex when you use string values. I dread to think about using floating point numbers.

Just a quick word when compiling your STOS programs. Once you have compiled it you should test it. Then fix it with the STOS fixer for the Falcon, available from Goodmans PDL. Then you may pack the program if you wish to.

I hope that all you people asking about compiler extensions will be satisfied now. If you need any further help write to me and I'll try to help. The best people to write to would be Mandarin or Francois Lionet but... say no more!

Watch out for part 3 where a simple installation program will feature allowing users to install your extension into their STOS work disc.
Until part 3, good bye!