Correct Maths Stack usage (CHRIX/RESRI)

Anything QL Software or Programming Related.
martyn_hill
Gold Card
Posts: 381
Joined: Sat Oct 25, 2014 9:53 am

Correct Maths Stack usage (CHRIX/RESRI)

Postby martyn_hill » Mon Feb 12, 2018 6:52 pm

Hi everyone

I am perplexed regarding a small point around correct use of the Maths stack. I am well acquainted with Mr. Dunbar's authoritative exposition on the subject (found on Dilwyn's site) - my favorite go-to reference on this knarly topic...

Then I read both the SMSQ Reference Guide, as well as numerous mentions littered throughout the SMSQ source code.

My question is this: Before calling the CHRIX/RESRI vector to check that/reserve sufficient space is available, is it necessary to pre-load A1 with the current value of BVRIP(a6)?

We know that we need to re-load A1 with BVRIP(a6) _after_ calling CHRIX/RESRI and before adjusting (sub) A1 with the required space ready for returning a value to SBasic (equal to what was asked for in the CHRIX/RESRI call.) and then saving the adjusted A1 back to BVRIP(a6).

That's all OK, but do we _really_ need to load A1 _before_ the vector call as well?

Mr. Dunbar doesn't mention such a requirement, yet QA.RESRI specifically states that A1 should point to the current Maths stack as a parameter on _entry_.

I did attempt to search the SMSQ source code to find the actual QA.RESI routine, but failed dismally.

Thoughts, my friends?


User avatar
NormanDunbar
Gold Card
Posts: 451
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: Correct Maths Stack usage (CHRIX/RESRI)

Postby NormanDunbar » Mon Feb 12, 2018 8:42 pm

Mr Dunbar? That's me! And perhaps a little formal. Call me scumbag instead! ;-)

Off the top of my head, when you enter into a function or procedure, written in assembly, the value in A1 has nothing at all to do with the maths stack!

If you call the parameter fetching routines, then it will be set correctly. If you have no parameters to fetch, and you need to return something, load A1 from BV_RIP(A6) or your function will die a horrible death on exit.


Here are some quotes from "the Book" (http://qdosmsq.dunbar-it.co.uk/download ... sembly.pdf) Pages 120 and onwards:

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 up 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:

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

Code: Select all

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.

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

Code: Select all

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

or

Code: Select all

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


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

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.

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.


HTH

Cheers,
Norm. (Aka Mr Dunbar!!!)


Why do they put lightning conductors on churches?
How come Tarzan never grew a beard?
If at first you don't succeed, don't take up skydiving!
User avatar
NormanDunbar
Gold Card
Posts: 451
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: Correct Maths Stack usage (CHRIX/RESRI)

Postby NormanDunbar » Mon Feb 12, 2018 8:51 pm

PS. If you need to allocate space on the stack for a result, and you already fetched some parameters, make sure that you allocate the space required minus the space used by the parameters.

I used to think it was ok to fetch, say, three FPs at 18 bytes, then ask for 24 to return 24 bytes (say a string) but I got crashed out so many times I went hunting and - although it was a long time ago - I found out that if you needed 24 bytes then don't make the stack any bigger, subtract the 18 for the 3 FPs from the 24 and allocate the spare 6 bytes.

Up until I wrote DJToolkit, which is where I encountered most of my maths stack problem areas, I was of the opinion, from books and articles in the then ever present magazines, that the stack could be treated with somewhat reckless abandon, as long as you didn't take things too far.

It was not the case. If you look in the DJToolkit source code, you will see that in "float_d1" and "integer_d1" I set d2 to be the number of bytes that I need for the result, minus the number I used on fetching parameters. I also load A1 from BV_RIP anyway!


Cheers,
Norm.


Why do they put lightning conductors on churches?
How come Tarzan never grew a beard?
If at first you don't succeed, don't take up skydiving!
martyn_hill
Gold Card
Posts: 381
Joined: Sat Oct 25, 2014 9:53 am

Re: Correct Maths Stack usage (CHRIX/RESRI)

Postby martyn_hill » Mon Feb 12, 2018 9:08 pm

Terrific, Norm thank you for clearing that up for me!

So, to test my understanding, here's a very simple NET% function what I wrote (simultaneously it seems with Mr Head's latest implementation in IPNet/Router), that I believe obeys all the rules for the simpler use-case of an SBasic FN with no params, returning an INT (please correct me if wrong!):

Code: Select all

* NET% FuNction definition
*  Simply returns the currently set NET Station Number (SELF) sv_netnr from $37(SYSVARS)
*
netf
         moveq    #mt.inf,d0         ;find the sysvars
         trap     #1

         moveq    #0,d5
         move.b   sv_netnr(a0),d5    ; fetch NET Station Number from $37(SYSVARS)

         move.l   bv_rip(a6),a1      ; fetch current stack ptr in to a1 - ready for CHRIX/RESRI - is this really needed? *** ND says YES!
         moveq    #2,d1              ; reserve 2xbytes for INT result
         move.w   bv_chrix,a2        ; check and make room if needed
         jsr      (a2)

         move.l   bv_rip(a6),a1      ; fetch (possibly updated) stack ptr in to a1
         suba.l   #2,a1              ; adjust for an INT result
         move.l   a1,bv_rip(a6)      ; update BV_RIP with new stack ptr

         move.w   d5,0(a6,a1.l)      ; store sv_netnr on the Maths stack
         moveq    #3,d4              ; flag an INT result
         moveq    #0,d0              ; flag no error
         rts


User avatar
NormanDunbar
Gold Card
Posts: 451
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: Correct Maths Stack usage (CHRIX/RESRI)

Postby NormanDunbar » Mon Feb 12, 2018 10:20 pm

Looks good to me Martyn.

If you have qmon/qmon2, put a breakpoint on it and see what's in A1 before you load it from BV_RIP. It won't be the stack! ;)

Qmon used to allow a trap #15 in your code to jump into the qmon monitor. That got removed from qmon2 for some reason. A big omission in my opinion.


Cheers,
Norm.


Why do they put lightning conductors on churches?
How come Tarzan never grew a beard?
If at first you don't succeed, don't take up skydiving!
User avatar
janbredenbeek
Trump Card
Posts: 249
Joined: Wed Jan 21, 2015 4:54 pm
Location: Hilversum, The Netherlands

Re: Correct Maths Stack usage (CHRIX/RESRI)

Postby janbredenbeek » Mon Feb 12, 2018 11:26 pm

Martyn, Norman,

There is no need to pre-load A1 with the value of BV.RIP. The 'Pennell bible' lists BV.CHRIX as having only one parameter (D1: amount of space needed) and A1 as 'preserved'.
Of course, you need to load A1 with BV.RIP(A6) afterwards since areas may have been moved.

Jan.


User avatar
NormanDunbar
Gold Card
Posts: 451
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: Correct Maths Stack usage (CHRIX/RESRI)

Postby NormanDunbar » Mon Feb 12, 2018 11:50 pm

Hi Jan,

I'm afraid I disagree. If a function takes no parameters, A1 is not a suitable maths stack pointer until loaded from BV_RIP. I speak from bitter experience.

None of the books mention it.

Unless SMSQ/E is differnt behaviour to QDOS. I feel an experiment coming on.....

Cheers,
Norm.


Why do they put lightning conductors on churches?
How come Tarzan never grew a beard?
If at first you don't succeed, don't take up skydiving!
User avatar
pjw
Gold Card
Posts: 375
Joined: Fri Jul 11, 2014 8:44 am
Location: Norway

Re: Correct Maths Stack usage (CHRIX/RESRI)

Postby pjw » Tue Feb 13, 2018 8:10 am

janbredenbeek wrote:Martyn, Norman,

There is no need to pre-load A1 with the value of BV.RIP. The 'Pennell bible' lists BV.CHRIX as having only one parameter (D1: amount of space needed) and A1 as 'preserved'.
Of course, you need to load A1 with BV.RIP(A6) afterwards since areas may have been moved.

Jan.

Yet the SMSQ/E Bible says:

Code: Select all

Vector $11A Reserve Room on Arithmetic Stack QA.RESRI
Call parameters                         Return parameters
D1.L Number of bytes required          D1 ???
D2                                     D2.L ???
D3                                     D3.L ???
A0                                     A0 Preserved
A1 Pointer to RI stack (rel. A6)       A1 ???
A2                                     A2 Preserved
A3                                     A3 Preserved
Error returns:
IMEM out of memory [SMSQ]
none [QDOS]

It may have been early days when Pennell wrote his book - or just a typo


Per
For every complex problem there is an answer that is clear, simple, and wrong.
- H. L. Mencken
User avatar
pjw
Gold Card
Posts: 375
Joined: Fri Jul 11, 2014 8:44 am
Location: Norway

Re: Correct Maths Stack usage (CHRIX/RESRI)

Postby pjw » Tue Feb 13, 2018 8:25 am

Martyn, may I suggest a wee tweak?

Code: Select all

         move.w   bv_chrix,a2        ; check and make room if needed
         jsr      (a2)
         sub.l    #2,bv_rip(a6)        ; adjust for an INT result
         move.l   a1,bv_rip(a6)      ; update BV_RIP with new stack ptr


It saves about six bytes and looks less "clunky". Just my two cents..


Per
For every complex problem there is an answer that is clear, simple, and wrong.
- H. L. Mencken
User avatar
pjw
Gold Card
Posts: 375
Joined: Fri Jul 11, 2014 8:44 am
Location: Norway

Re: Correct Maths Stack usage (CHRIX/RESRI)

Postby pjw » Tue Feb 13, 2018 8:31 am

PS: IIRC, on out of memory QDOS returns directly to SuperBASIC (with or without an ERR_OM?) while SMSQ/E returns an error code in D0. So perhaps your code should cater for this (admittedly unlikely) event?


Per
For every complex problem there is an answer that is clear, simple, and wrong.
- H. L. Mencken

Return to “Software & Programming”

Who is online

Users browsing this forum: No registered users and 1 guest