8. The Maths Stack

The maths stack is where all internal mathematical calculations of floating point variables are done. It is also used to allow parameters passed to machine code procedures and functions to be 'collected' from the user and passed to the registers etc for use by the procedure or function.

The maths stack is simply an area of memory which can be used for all these fancy calculations, parameter handling etc. There is nothing (much) special about it and it is ALWAYS addressed internally using register A1 (relative to A6 - but you knew that didn't you?)

One of the first things I learned when writing extensions to SuperBasic was that on entry to a function or procedure, the A1 register is set to a value corresponding to the top of the maths stack. This is a MYTH and is not correct.

The value in register A1 can be anything on entry to a machine code function or procedure. I have done a lot of investigating (thanks to QMON2) and come upi with the following rule :

If you want a suitable value in A1 for the top of the maths stack, then either fetch some parameters, or, load it from BV_RIP.

This means that if a function wants to return a value - which functions usually do - and the function has no parameters then you must load A1 from BV_RIP(A6) before calling the BV_CHRIX vector to reserve space. As I found out to my cost, not setting A1 is a good way to trash the system !

If your function does have parameters, then AFTER they have been fetched, A1 is set ok, up until that time, it is not and has the following possible values :

8.1. A1 Is Negative

If A1 is a negative number, then your function has been called as part of an expression such as :

PRINT 10 * MY_FUNCTION(p1, p2, p3 ....)

The number in A1.L is the number of bytes that have already been used on the maths stack for the '10' in this case. This will be -6 as the 10 will be stored as a floating point number.

8.2. A1 Is Zero

If the number in A1 is zero, then your function has been called thus :

PRINT MY_FUNCTION(p1, p2, p3 ....)

or

PRINT MY_FUNCTION(p1, p2, p3 ....) + 10

and no bytes have been used on the maths stack yet.

8.3. A1 Is Positive

If A1.L is greater than zero then this implies that there are A1.L many bytes available on the maths stack and calling bv_chrix to allocate stack space will not move the maths stack around in memory.

Warning

I have never seen this documented and it has been discovered by me during long debugging sessions. Now that SMSQ is here, the above information may no longer be valid. The only thing to remember is that on entry to a procedure or function, A1 does not hold a suitable value for the top of the maths stack as stated in various documents.

So that is the real situation and not as specified in the documentation. I took ages to debug one simple function I wrote, which had no parameters and required some space on the maths stack for its result. Take a look at the code in the colour functions (green, red etc) we wrote back at the start of this article and you will see the following code :

return_d7   move.l  bv_rip(a6),a1   ; Because we had no parameters passed
            moveq   #2,d1           ; Size of stack space required
            move.w  bv_chrix,a2     ; Routine to allocate maths stack space
            jsr     (a2)            ; Go get some space NO ERRORS OCCUR !

As you can now see, we load A1 from BV_RIP because none of the functions had any parameters passed. Had that one line of code been missed out, your QL would have crashed. Try it if you like !

Values on the maths stack must be stored at even addresses. For integers, long integers and floating point values, this is not a problem. Strings, on the other hand, must be set up correctly with the word defining the size n an even address and the bytes of the string following. Odd length strings should have an extra padding byte to keep the A1 maths stack pointer even.

If you read back to the section above entitled 'Keeping things even' then you will see how to do this. If you are returning a string from a function, you will need to reserve spoace for the string, its word count and a possible spare byte for padding. Refer to the explanation above and you will see why the following code 'just works' :

ret_string  move.w  (a0),d1         ; Assume the string to return in at (A0)
            addq.w  #3,d1           ; Size + 2 for word + 1 for padding if reqd
            bclr    #0,d1           ; Force even size
            move.w  bv_chrix,a2     ; Routine to allocate maths stack space
            jsr     (a2)            ; Go get some space NO ERRORS OCCUR !

Of course, I am assuming that A1 holds a suitable value. The code above will request an even amount of space for a string result. First we fetch the length into D1 - this is the number of characters in the string only.

We then add 3 to D1. This is 2 for the word count and one for a possible padding byte. By clearing bit zero of D1 we force the number to be even and can then carry on with the request for space etc. Easy stuff this !