Correct Maths Stack usage (CHRIX/RESRI)

Anything QL Software or Programming Related.
User avatar
janbredenbeek
Super Gold Card
Posts: 629
Joined: Wed Jan 21, 2015 4:54 pm
Location: Hilversum, The Netherlands

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by janbredenbeek »

pjw wrote: 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
Interesting! I have to delve deeper into the various disassemblies and Minerva/SMSQ source codes, but from the peeks I've done in the past into the various BV.CHxx routines I gathered that A1 has always been preserved (even the SMSQ/E code contains MOVEM.L Ax,-(A7) at the start and MOVEM.L (A7)+,Ax at the end). I couldn't find any instruction that stores A1 somewhere either (remember this call has various entry points for the different S*BASIC areas, which use D2.L as key to the pointer to the area to be moved).
I even remember a comment from Lau that it would be nice if BV.CHRIX would return A1 pointing to BV.RIP(A6) which would save programmers a MOVE instruction afterwards. However, if the original behaviour is to preserve A1, this would be prone to break software which relies on it...

regards, Jan.


User avatar
pjw
QL Wafer Drive
Posts: 1286
Joined: Fri Jul 11, 2014 8:44 am
Location: Norway
Contact:

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by pjw »

Mr Dunbar wrote: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. <>
Sometimes it is simpler to zero out what you have on the stack and start again, eg: You got one long (6 bytes), and want to return a word at the end, but you have other stuff going on that may require the use of the stack. The stack is never going to be shrunk while youre at it, although under QDOS it may move as a result of external events:

Code: Select all

	get one long
	move.l (a6,a1.l),d1
	addq.l #6,$58(a6)
..
	la di da
..
	bv.chrix and all that
	subq.l #2,$58(a6)
	move.l $58(a6),a1
	move.w dx,(a6,a1.l)
If you fetch multiple strings, however, things get rather fiddly, what with length counts and odd lengths. You can save yourself some trouble with the following shortcut:

Code: Select all

On entry to your funtion:
       move.l bv_rip(a6),d7        ;save "empty" stack pointer
       sub.l  bv_ribas(a6),d7      ;make it relative to BAS
       bsr.s  fetch_strings        ;fetch some strings (this may move the BASIC area)
..
       la di da
..
       add.l  bv_ribas(a6),d7      ;restore old relationship
       subq.l #2,d7					;leave room for integer return
       move.l d7,bv_rip(a6)        ;reset stack to status quo ante - 2
       move.l d7,a1
       move.w dx,(a6,a1.l)


Per
dont be happy. worry
- ?
User avatar
pjw
QL Wafer Drive
Posts: 1286
Joined: Fri Jul 11, 2014 8:44 am
Location: Norway
Contact:

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by pjw »

pjw wrote:
Mr Dunbar wrote: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. <>
Sometimes it is simpler to zero out what you have on the stack and start again, eg: You got one long (6 bytes), and want to return a word at the end, but you have other stuff going on that may require the use of the stack. The stack is never going to be shrunk while youre at it, although under QDOS it may move as a result of external events:

Code: Select all

	get one long
	move.l (a6,a1.l),d1
	addq.l #6,$58(a6)
..
	la di da
..
	subq.l #2,$58(a6)		; the ristack doesnt shrink mid-session
	move.l $58(a6),a1
	move.w dx,(a6,a1.l)
If you fetch multiple strings, however, things get rather fiddly, what with length counts and odd lengths. You can save yourself some trouble with the following shortcut:

Code: Select all

On entry to your funtion:
       move.l bv_rip(a6),d7        ;save "empty" stack pointer
       sub.l  bv_ribas(a6),d7      ;make it relative to BAS
       bsr.s  fetch_strings        ;fetch some strings (this may move the BASIC area)
..
       la di da
..
       add.l  bv_ribas(a6),d7      ;restore old relationship
       subq.l #2,d7					;leave room for integer return
       move.l d7,bv_rip(a6)        ;reset stack to status quo ante - 2
       move.l d7,a1
       move.w dx,(a6,a1.l)


Per
dont be happy. worry
- ?
User avatar
mk79
QL Wafer Drive
Posts: 1349
Joined: Sun Feb 02, 2014 10:54 am
Location: Esslingen/Germany
Contact:

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by mk79 »

NormanDunbar wrote: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.
You can have a permanent breakpoint using either dc.l $4afbedeb ("Enter DEBugger") or continue to use "trap #15", the latter however must be enabled by the command "tl 15" (IIRC "Trap Level 15") to enter QMON, otherwise it will be ignored.

Marcel


User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by NormanDunbar »

Thanks Marcel, that worked perfectly. Trap #15 once again brings QMON to the fore.

I added a TRAP #15 to DJToolkit's DJTK_VER$ function. This takes no parameters and returns a 4 character string, requiring 6 bytes on the stack.

PRINT DJTK_VER$

QMON was activated. A1 was set to zero.

PRINT 'xxxx' & DJTK_VER$

QMON was activated. A1 was set to FFFFFFFA or -6 which is the space used on the stack by the 4 character string plus its word count.


Thus, my assertion that on entry to a function, A1 is NOT a suitable value for the maths stack stands. :P :P :P Yah boo sucks! (Am I a plonker or what?)

Seriously, this is exactly what caused me lots of debugging way back when. Every book I had/have says that A1 will be a suitable value for the maths stack on entry to a function. None of my functions that took no parameters bothered to do anything with A1, so they simply blew up. It was only when QMON was bought/purchased and used that I finally discovered the anomalies - it's only set if you fetch some parameters and not if you don't.

HTH

Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
tofro
Font of All Knowledge
Posts: 2685
Joined: Sun Feb 13, 2011 10:53 pm
Location: SW Germany

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by tofro »

The only thing the "Technical Guide" claims is
The top of the arithmetic stack is usually pointed to by A1.
(So, that's apparently a book you don't have, Norm, but should) ;)

This is probably meant to say "you should make a1 point to it" and Pennel took it as "the system makes it point there".

My experience is the same: Without pulling parameters from BASIC or loading it from BV.CHRIX, a1 may point to anywhere but the math stack upon entering a BASIC FN or PROC.

Tobias


ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by NormanDunbar »

Hi Tofro.

I do have it, bit its a huge A4loose leaf binder rather than a book. I ptrefer books.


Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
janbredenbeek
Super Gold Card
Posts: 629
Joined: Wed Jan 21, 2015 4:54 pm
Location: Hilversum, The Netherlands

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by janbredenbeek »

This is what the QL Technical Manual says about BV.CHRIX:
BV.CHRIX is used to reserve space on the arithmetic stack (A6,A 1). On entry, the number of bytes required should be in D1.L: DO to D3 are smashed.
Since not only the stack but the whole SuperBASIC area may move during the call, the arithmetic stack pointer should be saved in BV_RIP(A6), whence it should be retrieved after the call has been completed.
However this doesn't say that on entry to a procedure or function A1 indeed points to the top of the RI stack. It only says that If you want to make sure there's enough room while you are doing something on the RI stack, you should save the current stack pointer to BV.RIP(A6), then call BV.CHRIX, and then retrieve A1 again from BV.RIP(A6). This is also what Pennell says.
In any case, BV.RIP(A6) should always point to the top of the RI stack but you should make no assumptions about A1 on entry, so always do a MOVE.L BV.RIP(A6),A1 before doing anything (if your procedure has parameters, you should first call the CA.GTxxx vectors anyway to evaluate them, which will also return (A6,A1.L) pointing to the top of the RI stack).

regards, Jan.


User avatar
janbredenbeek
Super Gold Card
Posts: 629
Joined: Wed Jan 21, 2015 4:54 pm
Location: Hilversum, The Netherlands

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by janbredenbeek »

Hi Norman,
NormanDunbar wrote:Thanks Marcel, that worked perfectly. Trap #15 once again brings QMON to the fore.

I added a TRAP #15 to DJToolkit's DJTK_VER$ function. This takes no parameters and returns a 4 character string, requiring 6 bytes on the stack.

PRINT DJTK_VER$

QMON was activated. A1 was set to zero.

PRINT 'xxxx' & DJTK_VER$

QMON was activated. A1 was set to FFFFFFFA or -6 which is the space used on the stack by the 4 character string plus its word count.

Thus, my assertion that on entry to a function, A1 is NOT a suitable value for the maths stack stands. :P :P :P Yah boo sucks! (Am I a plonker or what?)
Most procedures and functions have parameters, which must be evaluated first by calling the CA.GTxxx vectors. These return (A6,A1.L) pointing to the top of the RI stack.
However your function doesn't have a parameter so it doesn't have to call the CA.GTxxx vectors. In that case, you have to load A1 from BV.RIP(A6) first before putting the result on the stack (after calling BV.CHRIX first of course).

regards, Jan.


martyn_hill
Aurora
Posts: 909
Joined: Sat Oct 25, 2014 9:53 am

Re: Correct Maths Stack usage (CHRIX/RESRI)

Post by martyn_hill »

Hi everyone

Very interesting discussion - thank you!

If I may return to one of the original questions very briefly - "Must we pre-load a1 with bv_rip(a6) BEFORE calling CHRIX/RESRI?", can we agree that this step is unnecessary (contrary to the SMSQ reference guide and source code comments)?

Following Jan's comments, I've since perused the Minerva source and found chstk.asm which - as Jan mentioned - places no such requirement on a1 holding anything of interest before the relevant check/allocate (CHRIX just being the more common example.)

Still can't seem to find the equivalent module in the SMSQ source code, mind-you.


Post Reply