What does it mean by the GOSUB can be nested up to 8 level deep?

Daniel.A

New Member
Does it mean I can call up to 8 GOSUB in a subroutine? for example

Contacts:
Gosub A
Gosub B
Gosub c
Gosub d
Gosub e
Gosub f
Gosub g
Gosub h
Return
 

Haku

Senior Member
That's fine, you can gosub like that all day long as many times as you want, the nesting limit is when you gosub another subroutine from within a subroutine and do it several times, such as:

ProcOne:
Gosub ProcTwo
Return

ProcTwo:
Gosub ProcThree
Return

ProcThree:
Gosub ProcFour
Return

etc.

So you can only do that sort of nested gosub 8 levels deep, though I can't recall ever having to nest beyond once or twice so it's not a problem unless you get into some really complex programming.
 

eggdweather

Senior Member
There an interesting (well to me) analogy with HP calculators that use the Reverse-Polish-Notion (RPN) and they have a stack depth of 4, so up to 4 intermediate results can be stored, or in PICAXE parlance up to 3 sub-routines can be called from the main one (4 in total), anyway in the manual is the most complex equation I have ever seen given as example that even with that situation, 4 levels of stack are all that is required to work, so the PICAXE 8 limit is more than generous and rarely if ever will be met in practice.

Example (not HP's one) to work out (2+(2x12)/(1x2))*(4x9)=? on a RPN calculator you'd do:
2 ENTER (e.g. GOSUB level-1)
2 ENTER (e.g. GOSUB level-2)
12 ENTER (e.g. GOSUB level-3)
* (Now at GOSUB level-2)
1 ENTER (Now at GOSUB level-3)
2 ENTER (Now at GOSUB level-4)
* (Now at GOSUB level-3)
/ (Now at GOSUB level-2)
+ (Now at GOSUB level-1)
4 ENTER (Now at GOSUB level-2)
9 ENTER (Now at GOSUB level-3)
* (Now at GOSUB level-0)
Answer is 468
! and no brackets needed
 

hippy

Technical Support
Staff member
in PICAXE parlance up to 3 sub-routines can be called from the main one (4 in total)
A four level stack allows 4 subroutines plus the main routine, or eight plus main for the current PICAXE ...

Code:
#Picaxe 08M2
#Terminal 4800

Do
  SerTxd( CR, LF, "Start:" )
  Gosub Level1
Loop

Level1: SerTxd( "1" ) : Gosub level2 : Return
Level2: SerTxd( "2" ) : Gosub level3 : Return
Level3: SerTxd( "3" ) : Gosub level4 : Return
Level4: SerTxd( "4" ) : Gosub level5 : Return
Level5: SerTxd( "5" ) : Gosub level6 : Return
Level6: SerTxd( "6" ) : Gosub level7 : Return
Level7: SerTxd( "7" ) : Gosub level8 : Return
level8: SerTxd( "8" ) :                Return
 

BESQUEUT

Senior Member
... 4 levels of stack are all that is required to work, so the PICAXE 8 limit is more than generous and rarely if ever will be met in practice.
I just implemented exp function as recursive gosub... I have a level counter to know the recursivity depth. Furtunately, the function is converging before level 5, so there are few levels to call the function. But 8 levels are not to much !

Tried to go away (IE GOSUB Level 9) :

PE6 push a "stack overflow" windows and stops simulation.

OK for beginners, because this is probably an error.

BUT : how to really simulate a real Picaxe behavour ?
An option to show or not the "stack overflow" windows will be usefull.

If not checked, PE6 simulator have to do exactly the same thing as a real PIcaxe.
(No Picaxe at the moment to test...)
Code:
#picaxe 40X2
#no_table
#simspeed 1

Do
  SerTxd( CR, LF, "Start:" )
  Gosub Level1
Loop

Level1: SerTxd( ">1 " ) : Gosub level2 : SerTxd( "1< " ): Return
Level2: SerTxd( ">2 " ) : Gosub level3 : SerTxd( "2< " ): Return
Level3: SerTxd( ">3 " ) : Gosub level4 : SerTxd( "3< " ): Return
Level4: SerTxd( ">4 " ) : Gosub level5 : SerTxd( "4< " ): Return
Level5: SerTxd( ">5 " ) : Gosub level6 : SerTxd( "5< " ): Return
Level6: SerTxd( ">6 " ) : Gosub level7 : SerTxd( "6< " ): Return
Level7: SerTxd( ">7 " ) : Gosub level8 : SerTxd( "7< " ): Return
Level8: SerTxd( ">8 " ) : Gosub level9 : SerTxd( "8< " ): Return
Level9: SerTxd( ">9 " ) : Gosub level10 : SerTxd( "9< " ): Return
Level10: SerTxd( ">10 " ) : Gosub level11 : SerTxd( "10< " ): Return
level11: SerTxd( ">11 " ) :                Return
Recursive code example :
Code:
#picaxe 40X2
#no_table
#simspeed 1

Do
  SerTxd( CR, LF, "Start:" )
  b0=0
  Gosub Level
Loop

Level:
	inc b0
	SerTxd( ">",#b0," " )
	if b0<8 then gosub Level
	SerTxd( #b0,"< " )
	dec b0
	Return
 
Last edited:

eggdweather

Senior Member
Interesting. So I would do power(base x exp) and stop the recursion when exp=1

When the GOSUB limit is reached it wraps back to 1 (or 0)
 

BESQUEUT

Senior Member
Interesting. So I would do power(base x exp) and stop the recursion when exp=1
YES
Here is my "work in progress" :
Code:
#picaxe 40X2
#no_table
#simspeed 1



symbol EE=b0
symbol EEbit0=bit0

symbol WL=b2
symbol WH=b3
symbol WW=w1
symbol E_2=b4
symbol E10=b5
symbol Nb =b6
symbol BT=b7
symbol Reste=b8


symbol FL_ZM=w21
Symbol FL_TM=w22
symbol FL_ZE2=b46
symbol FL_TE2=b47

symbol WT=w24
symbol WTL=B48
symbol WTH=B49
symbol FL_XM=w25
symbol FL_XL=b50
symbol FL_XH=b51

symbol FL_YM=w26
symbol FL_YL=b52
symbol FL_YH=b53

symbol FL_XE2=b54
symbol FL_YE2=b55

#macro FL_Exp(Flott,E2,E)
	Nb=0
	FL_XM=Flott
	FL_XE2=E2
	EE=E
	gosub FLexp
#endmacro

#macro Expo2(E)
	E_2=E
	gosub Exp2
#endmacro

#macro ToFloat(F,E)
	WW=F
	E10=E
	gosub ToFlo
#endmacro

#macro FL_Add(Flott,E2)
	FL_YM=FL_XM : FL_YE2=FL_XE2
	FL_XM=Flott
	FL_XE2=E2
	gosub FLadd
#endmacro

#macro FL_Div(Flott,E2)
	FL_YM=FL_XM : FL_YE2=FL_XE2
	FL_XM=Flott
	FL_XE2=E2
	gosub FLdiv
#endmacro


#rem
FL_XM=40002 : FL_XE2=1
FL_YM=50000 : FL_YE2=1
gosub FLdiv

FL_XM=50000 : FL_XE2=1
FL_YM=40002 : FL_YE2=1
gosub FLdiv

FL_XM=40002 : FL_XE2=1
FL_YM=50000 : FL_YE2=3
gosub FLdiv
#endrem


#rem
	sertxd(13,10)
	FL_XM=32768
	FL_XE2=0
	FL_YM=32768
	FL_YE2=0
	gosub FL_Sertxd
	gosub FL_Sertyd
	sertxd ("FLmulti",13,10)
	gosub FLmulti
	gosub FL_Sertxd

	sertxd(13,10)
	FL_XM=50000
	FL_XE2=0
	FL_YM=12000
	FL_YE2=0
	gosub FL_Sertxd
	gosub FL_Sertyd
	sertxd ("FLmulti",13,10)
	gosub FLmulti
	gosub FL_Sertxd

	sertxd(13,10)
	FL_XM=50000
	FL_XE2=1
	FL_YM=12000
	FL_YE2=-2
	gosub FL_Sertxd
	gosub FL_Sertyd
	sertxd ("FLmulti",13,10)
	gosub FLmulti
	gosub FL_Sertxd


	FL_XM=33000:FL_XE2=0
	FL_Div(32768,-13)
	FL_Add(22000,4)
	gosub FL_sertxd
#endrem


	sertxd(13,10,"FL_Exp 2 0 15",13,10)
	FL_Exp(2,0,15)
	gosub FL_sertxd
	
	sertxd(13,10,"FL_Exp 3 0 3",13,10)
	FL_Exp(3,0,3)
	gosub FL_sertxd
	
	FL_ZM=FL_XM : FL_ZE2=FL_XE2
	
	sertxd(13,10,"FL_Exp 10 0 4",13,10)
	FL_Exp(10,0,4)
	FL_YM=FL_ZM : FL_YE2=FL_ZE2
	gosub FLmulti
	gosub FL_sertxd

	
#rem
	
	FL_YM=32768
	FL_YE2=-30
	gosub FLmul
	sertxd ("X=")
	gosub FL_sertxd
	sertxd (13,10)
	
	FL_Exp(3,0,5)
	sertxd ("3^5=",#FL_XM,"*2^",#FL_XE2,13,10,13,10)

	FL_Exp(2,12)
	sertxd ("2^12=",#WW,13,10,13,10)

	FL_Exp(2,-5)
	sertxd ("2^-5=",#WW,13,10,13,10)
	
	Expo2(0)
	sertxd ("2^0=",#WW," E" , #E_2,13,10)
	Expo2(4)
	sertxd ("2^4=",#WW," E" , #E_2,13,10)


	for nb=15 to 64
		Expo2(nb)
		sertxd ("2^",#nb,"=",#WW," E" , #E10,13,10)
	next nb
#endrem

#rem
	toFloat(1000,3)
	sertxd( #WW," E" , #E_2,13,10)
	
	toFloat(100,4)
	sertxd( #WW," E" , #E_2,13,10)
#endrem
end

FL_sertXd:
	if FL_XE2<128 then
		sertxd ("X=",#FL_XM,"*2^",#FL_XE2,13,10)
	else
		BT=-FL_XE2
		sertxd ("X=",#FL_XM,"*2^-",#BT,13,10)
	endif
return
FL_sertYd:
	if FL_YE2<128 then
		sertxd ("Y=",#FL_YM,"*2^",#FL_YE2,13,10)
	else
		BT=-FL_YE2
		sertxd ("Y=",#FL_YM,"*2^-",#BT,13,10)
	endif
return


ToFlo:
	sertxd(13,10,"Float(",#ww,",",#E10,")=")
	E_2=ncd WW
	E_2=16-E_2
	WW=WW<<E_2
return

Exp2:
	E10=0
	Reste=0
	if E_2=0 then
		WW=1
		
	elseif E_2 < 16 then
		WW=dcd E_2
		
	elseif E_2<128 then
		WW=32768		' ww=dcd 16
		EE=15
		b0=E_2-3
		do while EE<b0
			gosub Div10
		loop
	
		do while EE<E_2
			if WW<32768 then
				WW=WW<<1
				Reste=Reste<<1
				inc EE
			else
				gosub Div10
			endif
	      loop	
		WW=Reste+5/10+WW
	else
	endif

return

Div10:
	b0=ncd WW
	b0=16-b0
	Reste=Reste<<b0+5/10
	WW=WW<<b0+reste
	
	Reste=WW//5*2
	WW=WW/5
	EE=EE+b0+1
'	sertxd("WW=",#WW," EE=",#EE," R=", #Reste,13,10)
	inc E10
return


FLexp:
    sertxd ("FLexp Level=",#Nb," E=",#EE," ")
    GOSUB FL_sertxd
    inc Nb
    
    If EE = 0 Then
 	FL_XM=1
	  
 '   ElseIf EE = 1 Then ' answer is FL_XM
        
    ElseIf EE <128 Then
	  FL_YM=FL_XM : FL_YE2=FL_XE2
	  gosub FLmulti
	  sertxd ("X*X =>")
	  gosub FL_sertxd

	  If EEbit0 = 0 Then	' BT est pair
 '           Expon = Expon(X * X, Exp / 2)
		EE=EE/2
		if EE<>1 then gosub FLexp
		
		
        Else
'            Expon = X * Expon(X * X, (Exp - 1) / 2)
            EE=EE-1/2

		push FL_YL,FL_YH,FL_YE2
		if EE<>1 then gosub FLexp
		
		pop FL_YE2,FL_YH,FL_YL
		GOSUB FL_sertxd
		GOSUB FL_sertyd
		sertxd("X * Y",13,10)
		gosub FLmulti
	  End If
        
    Else
'        Expon = Expon(1 / X, -Exp)
	  EE=-EE
	  FL_YM=32768 : FL_YE2=-15
	  gosub FLdiv
	  gosub FLexp
   End If
return

' Effectue X=Y/X (Y est perdu dans l'op?ration)
FLdiv:
#rem
	wt=FL_YM/FL_XH-1
	sertxd (#FL_YM,"/",#FL_XH,"=",#Wt,13,10)
	w2=wt*/FL_XM
	sertxd ("W2=",#w2,13,10)
	w4=FL_YM-w2<<8/FL_XH>>1
	sertxd (#FL_YM,"-",#w2,"<<8/",#FL_XH,"=",#w4,13,10)
	FL_XM=wt<<7+w4
	sertxd ("WT=",#WT," X=",#FL_XM,13,10)
#endrem
	sertxd (#FL_YM," E2:",#FL_YE2,"/",#FL_XM," E2:",#FL_XE2,13,10)	
	FL_XE2=FL_YE2-FL_XE2	' on lib?re FL_YE2
	WT=FL_YM/FL_XH-1  	' 8 ou 9 premiers bits du dividande
	BT=ncd WT-8			' Combien de bits au dividande ?
	sertxd (#FL_YM,"/",#FL_XH,"=",#WT," E2=",#BT,13,10)
	
	FL_YE2=FL_XH		' On sauvegarde FL_XH
	FL_XM=WT*/FL_XM
	FL_YM=FL_YM-FL_XM<<8/FL_YE2>>BT	' En fait, on divise par FL_XM
	BT=8-BT
	FL_XM=WT<<BT+FL_YM
	FL_XE2=FL_XE2-BT-8
	
	gosub FL_sertxd
return

FLmul:
	FL_XM=FL_XM**FL_YM
	FL_XE2=FL_XE2+FL_YE2
return

FLmulti:	' X=X*Y et Y inchange
		' Accepte les flottants non normalis?s
	sertxd("FL_XM=",#FL_XM," * FL_YM=",#FL_YM,13,10)
	WT=FL_XM*FL_YM
	FL_XM=FL_XM**FL_YM
	sertxd("FL_XM**FL_YM=",#FL_XM,13,10)
	BT=ncd FL_XM
	FL_XE2=FL_XE2+FL_YE2
	
	sertxd("BT(**)=",#BT,13,10)
	if BT=0 then
		BT=ncd WT
		sertxd("BT(*)=" , #BT,13,10)		
		BT=16-BT
		FL_XM=WT<<BT
		FL_XE2=FL_XE2-BT
		
	else
		WT=WT>>BT
		BT=16-BT
		FL_XM=FL_XM<<BT+WT
		FL_XE2=FL_XE2-BT+16
	endif
return

FLadd:	' X=X+Y et Y inchange	
		' Accepte les flottants non normalises
	sertxd(13,10,"ADD",13,10)
	gosub FL_sertxd
	gosub FL_sertyd
	
	BT=FL_XE2-FL_YE2
	if BT<128 then
		FL_XM=FL_YM>>BT+FL_XM
	else
		BT=-BT
		FL_XM=FL_XM>>BT+FL_YM
	endif
return
Look at line 262 :
If EE = 0 Then FL_XM=1

NB : FL_XM can be read as "Floating X mantissa"

But now, I am stuck due to bug in PE6 simulator with ** operator...
 

SAborn

Senior Member
Am i wrong in thinking a GOSUB of 256 can be coded, and why would you need more then a few levels on gosub depth then a few for average code. i can only expect your code can be better written to work better. rather than your current method of many layers of gosub depths.
 

BESQUEUT

Senior Member
Am i wrong in thinking a GOSUB of 256 can be coded,
Yes you are wrong : only 8 levels are possible.
and why would you need more then a few levels on gosub depth then a few for average code. i can only expect your code can be better written to work better. rather than your current method of many layers of gosub depths.
And yes : any recursive program can also be written without recursivity.
Recursive style is more compact and work well if you don't reach the GOSUB depth limit.
Linear coding of same algorithm imply using of a stack, and fortunately Picaxe have Push and Pull commands.
So it is doable.

Recursive style is not "my method" !
It is a well documented and known computer programming tactic : Recursion_(computer_science)
 

hippy

Technical Support
Staff member
Writing elegant or well structured code can bring in deep nesting. For example a routine which can print hex word values to a number of outputs might initially be written as follows -

Code:
PrintHexWord:
  b10 = w0 / $0100 : Gosub PrintHexByte
  b10 = w0 & $00FF : Gosub PrintHexByte
  Return

PrintHexByte:
  b11 = b10 / $10 : Gosub PrintHexNibble
  b11 = b10 & $0F : Gosub PrintHexNibble
  Return

PrintHexNibble:
  b11 = b11 & $0F + "0"
  If b11 > "9" Then : b11 = b11 + 7 : End If
  Gosub PrintChar
  Return

PrintChar:
  If flgDebug Then
    SerTxd( b11 )
  End If
  HSerOut 0, ( b11 )
  Return
That is hitting four levels and the PrintHexWord routine would probably be called from within other subroutines. That could all be folded-down but arguably making it less elegant in the process.

Eight levels is usually enough for most PICAXE programs without worrying over any limits.
 

hippy

Technical Support
Staff member
Somewhere there was a switch from 8 to 16 levels. Is that method as old as I am? :)
Not sure that is correct. There used to be a limit of 16 GOSUB's in a program in total, and that was raised from 16 to 256. The stack depth was originally 4 but raised to 8.
 

tmfkam

Senior Member
And yes : any recursive program can also be written without recursivity.
Recursive style is more compact and work well if you don't reach the GOSUB depth limit.
Linear coding of same algorithm imply using of a stack, and fortunately Picaxe have Push and Pull commands.
So it is doable.

Recursive style is not "my method" !
It is a well documented and known computer programming tactic : Recursion_(computer_science)
Recursion when watched as it is working looks like programatic ballet! As one routine calls itself repeatedly it is like seeing an infinite number of Russian dolls being opened, only to find yet another doll inside. As the recursion reaches it's climax, the dolls slowly start being put back inside one another, one by one, eventually closing the last doll as the routine finally exits. Truly wonderful.

Of course if you've got any (programatic) dolls left over that haven't been put back inside the rest, you're in trouble...
 

BESQUEUT

Senior Member
Here is the answer for first code in #5 :
Start:>1 >2 >3 >4 >5 >6 >7 >8 >9 >10 >11 10< 9< 8< 7< 6< 5< 4< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3

So, a real Picaxe 40X2 go back everlastingly to the last GOSUB on his stack, in our case the one in Level3:
 
Last edited:

BESQUEUT

Senior Member
Recursion when watched as it is working looks like programatic ballet! As one routine calls itself repeatedly it is like seeing an infinite number of Russian dolls being opened...
Here is a very classical implementation of N! (as illustration)
Code:
#picaxe 40X2
#no_table
#simspeed 1

#macro Fact(N)
  	w1=1
	b1=N
	gosub Factorielle
#endmacro

Do
  for b0=2 to 6
  	Fact(b0)
	SerTxd( "Fact(",#b0,")=",#w1,13,10 )
  next b0
  sertxd(13,10)
Loop



Factorielle:
		w1=w1+1*w1
		dec b1
		if b1>1 then gosub Factorielle
Return
 

bpowell

Senior Member
Here is the answer for first code in #5 :
Start:>1 >2 >3 >4 >5 >6 >7 >8 >9 >10 >11 10< 9< 8< 7< 6< 5< 4< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3< 3

So, a real Picaxe go back everlastingly to the last GOSUB on his stack, in our case the one in Level3:
This isn't the result I got with a 08M2...I tried two different over-flow programs (including yours from post 5)...

When the 08M2 reached the "beginning" of it's return stack, and met another return, it appeared to crash...the process locked up, no more communication. I also had a parallel task running, blinking an LED...that also locked up hard. The 08M2 does not handle this gracefully.
 

Daniel.A

New Member
That's fine, you can gosub like that all day long as many times as you want, the nesting limit is when you gosub another subroutine from within a subroutine and do it several times, such as:

ProcOne:
Gosub ProcTwo
Return

ProcTwo:
Gosub ProcThree
Return

ProcThree:
Gosub ProcFour
Return

etc.

So you can only do that sort of nested gosub 8 levels deep, though I can't recall ever having to nest beyond once or twice so it's not a problem unless you get into some really complex programming.
Thanks. It is clear now. I haven't nested any of my subroutines even once.
 

SAborn

Senior Member
Yes you are wrong : only 8 levels are possible.
I think Hippy just confirmed you can go to 256 levels in gosubs, as it use to be less and you needed to select 256 in setup options, i think now its no setup required.

The stack depth is only 8.
 

inglewoodpete

Senior Member
I think Hippy just confirmed you can go to 256 levels in gosubs, as it use to be less and you needed to select 256 in setup options, i think now its no setup required.
Not 256 levels in gosubs but 256 gosub commands.

Ho hum - Actually its 255 gosub commands.
 

eggdweather

Senior Member
It looks like the interpreter uses a byte variable to hold the GOSUB references of 1-255 and does something like GOSUB 1 in effect
 

Technical

Technical Support
Staff member
Just to clarify, within a single program you can have up to 255 separate gosub/on gosub commands. In reality you will be very unlikely to hit this limit, as you would run out of memory space in a real program long before using up all the gosubs.

The 256'th position is reserved for the interrupt: sub-procedure, hence the reason there are 255 not 256.

These gosubs can then be nested inside each other 8 deep. Overflowing/underflowing the stack is nearly always down to bad coding, there should never be any need to do it.

Note that on..gosub can call multiple different sub-procedures, but only counts as 'one gosub', it is an often ignored, but actually quite useful, command.
 
Top