YES : good remark.I am not entirely sure what you are trying to achieve.
8 gosub commands each within the previous subroutine without any corresponding RETURN commands is the limit (stack depth for X1, X2 and M2 parts = 8)
Then one more GOSUB will result in stack overflow.
The example that you showed has more to do with poor programming practice than thecan we say that good practices to avoid stack overflow are :
- avoiding the GOTO command,
GOTO
command.myself: GOSUB myself
#no_end
No. The PICAXE return address stack, as said, is implemented as a circular buffer, so it eventually overwrites earlier things written to it.Does a PicAxe device not reset on a stack overflow?
You might be (partly) correct that it "always" crashes (on the 9th Return), but not that it (necessarily) Resets. Of course normally a crash is to be expected because the ninth Return would be to an incorrect (overwritten) address, (although theoretically it should be possible to predict what will happen ).Does a PicAxe device not reset on a stack overflow?
It does seem that the M2's may not behave as earlier PICAXE devices did and one can no longer rely on predictable behaviour if one overflows or underflows the return address stack.Therefore, it looks as if the (08M2) PICaxe Basic interpreter doesn't emulate (or use) the circular buffer entirely correctly?
As this is not so easy to explain to a beginner, I prefer saying :Don't overflow or underflow the stack and everything will be fine.
Better to "ban" the use of "GOSUB" (and the stack can't overflow)...do not use the GOTO command and everything will be fine...
Stirring the pot Alan? My suggestion would be to adhere to the rules of the chosen programming language and limitations of the hardware and learn, learn, learn from your mistakes, mistakes, mistakes!Hi,
Better to "ban" the use of "GOSUB" (and the stack can't overflow).
A "bad" programmer can use GOSUBs in place of GOTOs (to get the same effect) which may soon "overflow the stack" but probably not actually cause any "problems", until they try to use some RETURNs ! So start with GOTOs to teach the basics and when you want to introduce the concept of Subroutines, then use the CALL .. RETURN structure (which IMHO is more explicit terminology).
Remember that at the Assembler / Machine Code level, the "GOTO" (in the form of Jump, Branch, etc.) is the ONLY method of flow control that exists in some micros like the PIC.
Cheers, Alan.
I do notre agree.Hi,
Better to "ban" the use of "GOSUB" (and the stack can't overflow).
A "bad" programmer can use GOSUBs in place of GOTOs (to get the same effect) which may soon "overflow the stack" but probably not actually cause any "problems", until they try to use some RETURNs ! So start with GOTOs to teach the basics and when you want to introduce the concept of Subroutines, then use the CALL .. RETURN structure (which IMHO is more explicit terminology).
Remember that at the Assembler / Machine Code level, the "GOTO" (in the form of Jump, Branch, etc.) is the ONLY method of flow control that exists in some micros like the PIC.
Cheers, Alan.
As the "goto main" follows a "return", I don't think it can ever be executed, so it will not affect the stack. It just uses up a bit more programming space.The second "goto main" at the end of the program is significative.
......
GOTO PowerOnReset
SendByte:
......
GOSUB PowerOnReset
End
That's an interesting point. And I would agree you are correct.Of course we all know that what he really should have written is :
Code:GOSUB PowerOnReset End
PowerOnReset:
Gosub TheActualProgram
End
He should...That's an interesting point. And I would agree you are correct.AllyCat said:
Of course we all know that what he really should have written is :
Code:
GOSUB PowerOnReset
End
As a "purist" I agree that it can be a very interesting challenge to optimize size and/or speed...a programmer should not take it upon themselves to optimise.
And the counter there is; "true, but we know it doesn't. If one wants that kind of optimisation one has to do it oneself".
So, accepting that purist code is best, where does that leave us when less than purist code is actually better ?
I think it comes down to how one measures it, what one's criteria is for best or better, that there's no absolute there.
I have (finally) got around to trying this on a base PIC device. This code is running on a 12F1840:A base PIC device always appears to reset on overflow. Though after I originally posted that I did wonder if when the pointer returned to the first address on the stack, if that was the startup routine which initialises the program it would appear to an observer (me!) to have reset, when in fact it had simply returned to the startup routine. I will have to look and see which is the case.
#Chip 12F1840,32
'(c)Tmfkam 2019
#Define D_Data PortA.5 'Pin 2
#Define D_Clk1 PortA.4 'Pin 3
#Define D_Lat PortA.2 'Pin 5
Dir D_Clk1 Out
Dir D_Data Out
Dir D_Lat Out
Dim Clocks As Byte
Dim Jump As Bit
ClearDisplay
Let Jump = 0
Let D_Lat = 0
ShiftData(206) 'R
ShiftData(227) 'u
ShiftData(171) 'n
ShiftData(255) 'Space
Let D_Lat = 1
Wait 500 mS
Do
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
ShiftData(192) '0
Let D_Lat = 1
Wait 2000 mS
Sub1
If Jump = 0 Then
Sub2
Sub3
Sub4
Sub5
Sub6
Sub7
Sub8
Sub9
SubA
SubB
SubC
SubD
SubE
SubF
SubG
SubH
SubI
SubJ
SubK
SubL
Let Jump = 1
Else
Let Jump = 0
End If
Let D_Lat = 0
ShiftData(134) 'E
ShiftData(171) 'n
ShiftData( 33) 'd.
If Jump = 1 Then
ShiftData(255-128) 'Space.
Else
ShiftData(255) 'Space
End If
Let D_Lat = 1
Wait 5000 mS
Loop
Sub Sub1
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(249-128) '1.
Else
ShiftData(249) '1
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
Sub2
End If
End Sub
Sub Sub2
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(164-128) '2.
Else
ShiftData(164) '2
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
Sub3
End If
End Sub
Sub Sub3
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(176-128) '3.
Else
ShiftData(176) '3
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
Sub4
End If
End Sub
Sub Sub4
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(153-128) '4.
Else
ShiftData(153) '4
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
Sub5
End If
End Sub
Sub Sub5
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(146-128) '5.
Else
ShiftData(146) '5
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
Sub6
End If
End Sub
Sub Sub6
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(130-128) '6.
Else
ShiftData(130) '6
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
Sub7
End If
End Sub
Sub Sub7
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(248-128) '7.
Else
ShiftData(248) '7
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
Sub8
End If
End Sub
Sub Sub8
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(128-128) '8.
Else
ShiftData(128) '8
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
Sub9
End If
End Sub
Sub Sub9
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(152-128) '9.
Else
ShiftData(152) '9
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubA
End If
End Sub
Sub SubA
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(136-128) 'A.
Else
ShiftData(136) 'A
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubB
End If
End Sub
Sub SubB
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(131-128) 'b.
Else
ShiftData(131) 'b
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubC
End If
End Sub
Sub SubC
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(198-128) 'C.
Else
ShiftData(198) 'C
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubD
End If
End Sub
Sub SubD
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(161-128) 'd.
Else
ShiftData(161) 'd
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubE
End If
End Sub
Sub SubE
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(134-128) 'E.
Else
ShiftData(134) 'E
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubF
End If
End Sub
Sub SubF
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(142-128) 'F.
Else
ShiftData(142) 'F
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubG
End If
End Sub
Sub SubG
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(194-128) 'G.
Else
ShiftData(194) 'G
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubH
End If
End Sub
Sub SubH
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(137-128) 'H.
Else
ShiftData(137) 'H
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubI
End If
End Sub
Sub SubI
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(239-128) 'i.
Else
ShiftData(239) 'i
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubJ
End If
End Sub
Sub SubJ
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(241-128) 'J.
Else
ShiftData(241) 'J
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubK
End If
End Sub
Sub SubK
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(139-128) 'k.
Else
ShiftData(139) 'k
End If
Let D_Lat = 1
Wait 500 mS
If Jump = 1 Then
SubL
End If
End Sub
Sub SubL
Let D_Lat = 0
ShiftData(146) 'S
ShiftData(227) 'u
ShiftData( 3) 'b.
If Jump = 1 Then
ShiftData(199-128) '5.
Else
ShiftData(199) 'L
End If
Let D_Lat = 1
Wait 500 mS
End Sub
Sub ClearDisplay
Let D_Lat = 0
ShiftData(255) 'Space
ShiftData(255) 'Space
ShiftData(255) 'Space
ShiftData(255) 'Space
Let D_Lat = 1
End Sub
Sub ShiftData (DataOut As Byte)
For Clocks = 1 to 8
Let D_Clk1 = 0
Let D_Data = DataOut.7
Let D_Clk1 = 1
Rotate DataOut Left Simple
Next Clocks
End Sub