Assistance required - Using RNDX (BBC Micro)

Discuss all aspects of programming here. From 8-bit through to modern architectures.
Post Reply
FelisSapien
Posts: 8
Joined: Sun Apr 15, 2018 4:17 pm
Location: UK
Contact:

Assistance required - Using RNDX (BBC Micro)

Post by FelisSapien » Thu Jun 28, 2018 4:03 pm

Hi all, since introducing myself to the board I've been pretty silent but as I've had time I've been chipping away at my project.

Nothing challenging to you old hands but something to help me orient myself with the Model B... In short it's a Flood-it type game. I've something mostly complete now with the core control and input handled in BASIC and the grunt elements in assembly. There's no doubt been an unbelievable amount of unnecessary diversions and wheel reinvention but that seems to be the approach I need to take to learn. Anyhow...

I'm trying to use the RNDX routine to generate the play area, and I've come unstuck... From the BASIC ROM User Guide it appears that I should be able to do this and to some degree I can, in that the numbers I need are generated. The issues become apparent when control returns to the BASIC code. If I contain the calls to 'my' routine in a procedure then I get an 'at line X' message when returning from the proc. X will be the line I call the procedure from. If I keep the call to my code in the mainline code then processing will appear to continue but odd things will happen further into the run. The odd things vary depending on how many numbers I generate.

I've stripped things back to a contained test case. The issue is apparent even when making a single call to RNDX. Can anyone help me determine what's going on?

Code: Select all

rndx 		=&AF24 
colrs		=&81:?colrs=5

PROC_assemble
PRINT "START"
PROC_randomize
PRINT "END"
END

 
DEF PROC_randomize
	CALL rndxtest:PRINT !result;
ENDPROC
 
DEF PROC_assemble
	 DIM mc% 200
	 FOR pass% = 0 TO 2 STEP 2
	 P% = mc%
	 [OPT pass%
	 .result    EQUD 0
	            EQUB 0
	 .rndxtest
	    LDA &6              \ HIMEM lo
	    STA &4              \ save in &4
	    LDA &7              \ HIMEM hi
	    STA &5              \ save in &5
	    LDA colrs	        \ get next byte of rndxval
	    LDX #0              \ zeroise loop counter	    
	    STA &2A,X           \ save in IWA
	    STX &2B
	    STX &2C
	    STX &2D
	    JSR rndx            \ do rndx
	    JSR saveiwa         \ copy IWA into result
	    RTS                 \ bye bye
	 .saveiwa
	    LDX #0              \ zeroise loop counter
	 .loopiwa
	    LDA &2A,X           \ get next byte of IWA
	    STA result,X        \ save in result
	    INX                 \ bump X
	    CPX #4              \ end of loop ?
	    BCC loopiwa         \ no - back
	    RTS                 \ back
	 ]
	 NEXT pass%
ENDPROC 
Although I've stripped away the code (I think) I don't need, this is pretty much the code as presented in the RNDX example of the BASIC ROM User Guide.

Another approach I'm considering is to hack together a routine specific to my case, but I think I'd rather sort this if I can and and move on. As mentioned above this was mostly intended as an exercise to help get me started. I'd be nice to move on to something fresh, though I've no firm plans as to what that might be...

Many thanks,
Carl
Last edited by FelisSapien on Thu Jun 28, 2018 4:07 pm, edited 1 time in total.

User avatar
lurkio
Posts: 1779
Joined: Tue Apr 09, 2013 11:30 pm
Location: Doomawangara
Contact:

Re: Assistance required - Using RNDX (BBC Micro)

Post by lurkio » Thu Jun 28, 2018 5:15 pm

Your code works if you replace the call to PROC_randomize with the actual body of the procedure (CALL rndxtest:PRINT !result;).

Not sure why though!

:?:

Code: Select all

rndx 		=&AF24 
colrs		=&81:?colrs=5

PROC_assemble
PRINT "START"
CALL rndxtest:PRINT !result;
PRINT "END"
END

 
DEF PROC_randomize
	CALL rndxtest:PRINT !result;
ENDPROC
 
DEF PROC_assemble
	 DIM mc% 200
	 FOR pass% = 0 TO 2 STEP 2
	 P% = mc%
	 [OPT pass%
	 .result    EQUD 0
	            EQUB 0
	 .rndxtest
	    LDA &6              \ HIMEM lo
	    STA &4              \ save in &4
	    LDA &7              \ HIMEM hi
	    STA &5              \ save in &5
	    LDA colrs	        \ get next byte of rndxval
	    LDX #0              \ zeroise loop counter	    
	    STA &2A,X           \ save in IWA
	    STX &2B
	    STX &2C
	    STX &2D
	    JSR rndx            \ do rndx
	    JSR saveiwa         \ copy IWA into result
	    RTS                 \ bye bye
	 .saveiwa
	    LDX #0              \ zeroise loop counter
	 .loopiwa
	    LDA &2A,X           \ get next byte of IWA
	    STA result,X        \ save in result
	    INX                 \ bump X
	    CPX #4              \ end of loop ?
	    BCC loopiwa         \ no - back
	    RTS                 \ back
	 ]
	 NEXT pass%
ENDPROC 
Last edited by lurkio on Thu Jun 28, 2018 5:16 pm, edited 1 time in total.

User avatar
MartinB
Posts: 4979
Joined: Mon Mar 31, 2008 9:04 pm
Location: Obscurity
Contact:

Re: Assistance required - Using RNDX (BBC Micro)

Post by MartinB » Thu Jun 28, 2018 6:51 pm

Locations $0004 and $0005 that you write to in your assembler ditty are BASIC's stack pointer so you are trashing its return path for the PROC. This is why lurkio's change works because it gets rid of any PROC and return.

User avatar
lurkio
Posts: 1779
Joined: Tue Apr 09, 2013 11:30 pm
Location: Doomawangara
Contact:

Re: Assistance required - Using RNDX (BBC Micro)

Post by lurkio » Thu Jun 28, 2018 8:08 pm

MartinB wrote:
Thu Jun 28, 2018 6:51 pm
Locations $0004 and $0005 that you write to in your assembler ditty are BASIC's stack pointer so you are trashing its return path for the PROC. This is why lurkio's change works because it gets rid of any PROC and return.
Well spotted! Not sure why the book says to do that. The code works as is if you comment out the offending lines:

Code: Select all

rndx 		=&AF24 
colrs		=&81:?colrs=5

PROC_assemble
PRINT "START"
PROC_randomize
PRINT "END"
END

 
DEF PROC_randomize
	CALL rndxtest:PRINT !result;
ENDPROC
 
DEF PROC_assemble
	 DIM mc% 200
	 FOR pass% = 0 TO 2 STEP 2
	 P% = mc%
	 [OPT pass%
	 .result    EQUD 0
	            EQUB 0
	 .rndxtest
	    \LDA &6              \ HIMEM lo
	    \STA &4              \ save in &4
	    \LDA &7              \ HIMEM hi
	    \STA &5              \ save in &5
	    LDA colrs	        \ get next byte of rndxval
	    LDX #0              \ zeroise loop counter	    
	    STA &2A,X           \ save in IWA
	    STX &2B
	    STX &2C
	    STX &2D
	    JSR rndx            \ do rndx
	    JSR saveiwa         \ copy IWA into result
	    RTS                 \ bye bye
	 .saveiwa
	    LDX #0              \ zeroise loop counter
	 .loopiwa
	    LDA &2A,X           \ get next byte of IWA
	    STA result,X        \ save in result
	    INX                 \ bump X
	    CPX #4              \ end of loop ?
	    BCC loopiwa         \ no - back
	    RTS                 \ back
	 ]
	 NEXT pass%
ENDPROC 
:idea:
Last edited by lurkio on Thu Jun 28, 2018 10:49 pm, edited 3 times in total.

FelisSapien
Posts: 8
Joined: Sun Apr 15, 2018 4:17 pm
Location: UK
Contact:

Re: Assistance required - Using RNDX (BBC Micro)

Post by FelisSapien » Thu Jun 28, 2018 8:33 pm

=D> Thanks guys, much appreciated. I'll apply that change to my game routine and report back.

User avatar
jgharston
Posts: 3243
Joined: Thu Sep 24, 2009 11:22 am
Location: Whitby/Sheffield
Contact:

Re: Assistance required - Using RNDX (BBC Micro)

Post by jgharston » Thu Jun 28, 2018 11:58 pm

FelisSapien wrote:
Thu Jun 28, 2018 4:03 pm

Code: Select all

(snip)
	 .rndxtest
	    LDA &6              \ HIMEM lo
	    STA &4              \ save in &4
	    LDA &7              \ HIMEM hi
	    STA &5              \ save in &5
That's not "saving" HIMEM in 4/5, it's clearing the stack pointer in 4/5 by setting it to HIMEM. If comments lie like this it's no wonder the code can't be understood. Presumably there's a reason to clear the BASIC stack, but as you've discovered, it destroys any ability to call the code from within a subroutine.

Code: Select all

$ bbcbasic
PDP11 BBC BASIC IV Version 0.25
(C) Copyright J.G.Harston 1989,2005-2015
>_

User avatar
lurkio
Posts: 1779
Joined: Tue Apr 09, 2013 11:30 pm
Location: Doomawangara
Contact:

Re: Assistance required - Using RNDX (BBC Micro)

Post by lurkio » Fri Jun 29, 2018 12:45 am

jgharston wrote:
Thu Jun 28, 2018 11:58 pm
Presumably there's a reason to clear the BASIC stack
What do you think the reason is, in this context (i.e. when calling the "rndx" routine (&AF24) in the BASIC ROM)?

The only relevant bit from the Advanced BASIC ROM User Guide seems to be this:
BASIC has its own stack located immediately below HIMEM. Like the processor stack, it runs downwards in memory. The stack is maintained by a set of subroutines within the BASIC ROM. A stack pointer is held in &4 and &5 (lo,hi). Generally, whenever BASIC has two integer fields to process, one will be located in the IWA [&2A..&2D] while the other is in the stack, pointed to by &4 and &5. When using BASIC routines we shall usually load one integer into the IWA and point &4,&5 at the other.
But that doesn't explain why you should clear the stack in the case of "rndx", which seems to process only one "integer field".

:?:

User avatar
1024MAK
Posts: 7985
Joined: Mon Apr 18, 2011 4:46 pm
Location: Looking forward to summer in Somerset, UK...
Contact:

Re: Assistance required - Using RNDX (BBC Micro)

Post by 1024MAK » Fri Jun 29, 2018 3:09 pm

If it's a stack, surely you should update the pointer when you stack a value rather than clearing the pointer back to the beginning of the stack? Otherwise it's not being used as a stack...

Mark

Post Reply