Working example showing Slots with Return stack and Parm stack
TimC
Posts: 77
Hi All,
Been looking through some old code to try to understand how to use Slots. To make them easier and provide more local variables to work with.
Most of the work was started years ago by Tracy Allen and others. I think I improved on a bit but it does take time to get used to.
For example in normal basic you would write a line: Gosub xPrintEEDATA(char) which runs a routine with one parameter and returns.
In my example it looks like this:
GoToX=xPrintEEDATA : ReturnPointer=ReturnPointer-1 : PUT ReturnPointer,xDispMsg1
ParmPointer=ParmPointer-1 : PUT ParmPointer,char : RUN GoToSlot : DispMsg1:
You could read the two lines as: ' 1:where are we going, 2:How are we getting back, 3:What are we passing 4:Our RETURN label
Without a macro language or a pre-processor it's never going to look neat and tidy.
The Quick flow of the program is this:
Slot 0 EnterMessage
passes to
Slot 1 GetMsgNum
returns to
Slot 0 ShowMessage
passes to
Slot 1 DispMsg
passes to
Slot 2 Print
returns to
Slot 1 DispMsg
returns to
Slot 0 Final
There is more than that but if you run the program is self documents where it is and where it's going and how it is going to return.
Uncomment the '#DEFINE DebugMode lines to see more detail or debug.
The Console output should look like this:
Starting MultiSlot program. It's got slots and stacks oh my!
---> Hi there! Type in your new message now (CR finishes) <---
Just Testing.
What message # to Display (0-5)?
0
Our Message # is:0
Just Testing.
Return Stack is empty. ReturnPointer is Zer0. No Problems
**** FINI ****
Hope someone finds this usefull
Regards
Tim C.
****** LOOK FOR NEWER VERSION BELOW, EASIER TO USE, FIXED SOME BUGS *******
Here is the Main Program
Here is the First Slot Program:
Second and Last Slot
Been looking through some old code to try to understand how to use Slots. To make them easier and provide more local variables to work with.
Most of the work was started years ago by Tracy Allen and others. I think I improved on a bit but it does take time to get used to.
For example in normal basic you would write a line: Gosub xPrintEEDATA(char) which runs a routine with one parameter and returns.
In my example it looks like this:
GoToX=xPrintEEDATA : ReturnPointer=ReturnPointer-1 : PUT ReturnPointer,xDispMsg1
ParmPointer=ParmPointer-1 : PUT ParmPointer,char : RUN GoToSlot : DispMsg1:
You could read the two lines as: ' 1:where are we going, 2:How are we getting back, 3:What are we passing 4:Our RETURN label
Without a macro language or a pre-processor it's never going to look neat and tidy.
The Quick flow of the program is this:
Slot 0 EnterMessage
passes to
Slot 1 GetMsgNum
returns to
Slot 0 ShowMessage
passes to
Slot 1 DispMsg
passes to
Slot 2 Print
returns to
Slot 1 DispMsg
returns to
Slot 0 Final
There is more than that but if you run the program is self documents where it is and where it's going and how it is going to return.
Uncomment the '#DEFINE DebugMode lines to see more detail or debug.
The Console output should look like this:
Starting MultiSlot program. It's got slots and stacks oh my!
---> Hi there! Type in your new message now (CR finishes) <---
Just Testing.
What message # to Display (0-5)?
0
Our Message # is:0
Just Testing.
Return Stack is empty. ReturnPointer is Zer0. No Problems
**** FINI ****
Hope someone finds this usefull
Regards
Tim C.
****** LOOK FOR NEWER VERSION BELOW, EASIER TO USE, FIXED SOME BUGS *******
Here is the Main Program
' =========================================================================
'
' File...... MsgMaster.bsp
' Purpose... Program for slot demo showing stacks.
'
' Author.... TimC. (based on code from Chris Anderson, Tracy Allen and Parallax)
' E-mail....
' Started... 30 Mar 2020
' Updated...
' Tim Comments... Working Great!!!
'
' {$STAMP BS2p, MsgSlot1, MsgSlot2}
' {$PBASIC 2.5}
'
' =========================================================================
' --- scratch pad assignments
ReturnPointerTop CON 62 ' will be initial value of stack pointer
ParmPointerTop CON 52 ' will be initial value of Parm pointer
' --- variable assignments
DataPointer VAR Word ' Used as an address pointer for DATA statements
ReturnPointer VAR Byte ' stack pointer--do not use for anything else!
ParmPointer VAR Byte ' Parm pointer--do not use for anything else!
GoToX VAR Byte ' for bank switching
GoToSlot VAR GoToX.nib1 ' target bank for RUN
GoToLabel VAR GoToX.nib0 ' target routine from BRANCH within bank
cat VAR GoToX ' this byte can be reused within bank
char VAR Byte ' for demo, preserved across banks
' an index for the message to retrieve
temp VAR Byte
temp2 VAR Byte
' --- crossbank labels targets ----
xInit CON $00 ' bank 0 targets
xEnterMessage CON $01
xShowMessage CON $02
xFinal CON $03
xDispMsg CON $10 ' bank 1 targets
xDispMsg1 CON $11
xGetMsgNum CON $12
xPrintEEDATA CON $21 ' bank 2 targets
'#DEFINE DebugMode 'Follow along on the console
' ----------------------------------------------------
' --- top of program
' sxGoTo is $00 at reset ---> branch to top
BRANCH GoToLabel,[Init,EnterMessage,showmessage,Final]
Init:
ReturnPointer=ReturnPointerTop ' initialize the return stack
ParmPointer=ParmPointerTop ' initialize the Parm stack
PAUSE 700
DEBUG 0,"Starting MultiSlot program. It's got slots and stacks oh my!",CR
EnterMessage: ' get a new message from the serial port
#IF DebugMode #THEN DEBUG "inside slot 0 get message 0,1",CR #ENDIF
DEBUG "---> Hi there! Type in your new message now (CR finishes) <---",CR
STORE 2 ' All my data is in Slot 2
DataPointer = 0 ' reset data pointer
char = " " ' else first character would be a 0 and erase screen
DO
WRITE DataPointer,char ' Write to the EEPROM
DEBUGIN STR char\1 ' Read in one character from the console
DataPointer=DataPointer+1 ' Inc to next EEPROM Location
LOOP UNTIL (char = CR) ' enter key finishes input
WRITE DataPointer,0 ' write end of line char
char=0 'points to the message we just typed in
'This is our first slot style GoTo. Read the line as: Where we Going and how are we getting back
GoToX=xGetMsgNum : ReturnPointer=ReturnPointer-1 : PUT ReturnPointer,xShowMessage
#IF DebugMode #THEN DEBUG "GoTo is Now=", HEX2 GoToX, " ReturnPointer =", SDEC ReturnPointer - ReturnPointerTop, ".",CR #ENDIF
RUN GoToSlot ' GoTo get the new message
ShowMessage:
#IF DebugMode #THEN DEBUG "inside slot 0 show message number 0,2",CR #ENDIF
DEBUG "Our Message # is:",DEC char, CR 'This is all we do in ShowMessage, Just show the Message #
'Slot style GoToSUB with a parm
GoToX=xDispMsg : ReturnPointer=ReturnPointer-1 : PUT ReturnPointer,xFinal ' stack the return target in this bank
ParmPointer=ParmPointer-1 : PUT ParmPointer,char ' put the parameter char on the stack too
RUN GoToSlot ' GoTo show the message #X
Final:
IF char=6 THEN EnterMessage
#IF DebugMode #THEN DEBUG "Inside slot 0 Label text 0,3",CR #ENDIF
'-----
GET ReturnPointer,char
ReturnPointer = ReturnPointer - ReturnPointerTop
IF ReturnPointer = 0 AND char=0 THEN
DEBUG "Return Stack is empty. ReturnPointer is Zer0. No Problems",CR
ELSE
DEBUG "Return Stack = ", DEC ReturnPointer, " Return Address = ", HEX char, ". There is a problem."
ENDIF
DEBUG "**** FINI ****", CR
PAUSE 700
END
Here is the First Slot Program:
' =========================================================================
'
' File...... MsgSlot1.bsp
' Purpose... Program for slot demo showing stacks.
'
' Author.... TimC. (based on code from Chris Anderson, Tracy Allen and Parallax)
' E-mail....
' Started... 30 Mar 2020
' Updated...
' Tim Comments... Working Great!!!
'
' {$STAMP BS2p}
' {$PBASIC 2.5}
'
' =========================================================================
' DATA section, messages in eeprom.
ReturnPointerTop CON 62 ' will be initial value of stack pointer
ParmPointerTop CON 52 ' will be initial value of Parm pointer
' variable assignments
DataPointer VAR Word ' Used as an address pointer for DATA statements (if more than 256 bytes of DATA)
ReturnPointer VAR Byte ' stack pointer--do not use for anything else!
ParmPointer VAR Byte ' Parm pointer--do not use for anything else!
GoToX VAR Byte ' for bank switching
GoToSlot VAR GoToX.nib1 ' target bank for RUN
GoToLabel VAR GoToX.nib0 ' target routine from BRANCH within bank
cat VAR GoToX ' this byte can be reused within bank
char VAR Byte ' for demo, preserved across banks
' an index for the message to retrieve
temp VAR Byte
temp2 VAR Byte
' --- crossbank labels targets ----
xInit CON $00 ' bank 0 targets
xEnterMessage CON $01
xShowMessage CON $02
xFinal CON $03
xDispMsg CON $10 ' bank 1 targets
xDispMsg1 CON $11
xGetMsgNum CON $12
xPrintEEDATA CON $21 ' bank 2 targets
'#DEFINE DebugMode 'Follow along on the console
' ----------------------------------------------------
' --- top of program
BRANCH GoToLabel,[dispmsg,dispmsg1,GetMsgNum]
' --- display the stored message
' Calls a second routine to actually print the message
DispMsg:
#IF DebugMode #THEN DEBUG "inside Display message slot 1,0",CR #ENDIF
GET ParmPointer,char : ParmPointer=ParmPointer+1 ' retrieve (pop) the parm we need
#IF DebugMode #THEN DEBUG "** Display Message #", DEC1 char, ". **",CR #ENDIF
' as close to a gosub parm subroutine: Gosub xPrintEEDATA(char) as we can make it all compressed in 2 lines
' What's in these 2 lines: Don't forget the branch edit above.
' 1:where are we going, 2:How are we getting back, 3:What are we passing 4:Our RETURN label
GoToX=xPrintEEDATA : ReturnPointer=ReturnPointer-1 : PUT ReturnPointer,xDispMsg1
ParmPointer=ParmPointer-1 : PUT ParmPointer,char : RUN GoToSlot : DispMsg1:
GET ReturnPointer,GoToX : ReturnPointer=ReturnPointer+1 ' retrieve (pop) the return vector
#IF DebugMode #THEN DEBUG "GoTo is Now=", HEX2 GoToX, " ReturnPointer=", SDEC ReturnPointer-ReturnPointerTop, ".",CR #ENDIF
RUN GoToSlot ' do it, return to bank 0
' --- get a user message and store it in eeprom in this bank
GetMsgNum:
#IF DebugMode #THEN DEBUG "inside get message slot 1,1",CR #ENDIF
DEBUG "What message # to Display (0-5)?",CR
DEBUGIN DEC1 char : DEBUG CR
GET ReturnPointer,GoToX : ReturnPointer=ReturnPointer+1 ' get (pop) the return vector
#IF DebugMode #THEN DEBUG "GoTo is Now=", HEX2 GoToX, " ReturnPointer=", SDEC ReturnPointer-ReturnPointerTop, ".",CR #ENDIF
RUN GoToSlot ' GoTo back to bank 0 target
Second and Last Slot
' =========================================================================
'
' File...... MsgSlot2.bsp
' Purpose... Program for slot demo showing stacks.
'
' Author.... TimC. (based on code from Chris Anderson, Tracy Allen and Parallax)
' E-mail....
' Started... 30 Mar 2020
' Updated...
' Tim Comments... Working Great!!!
'
' {$STAMP BS2p}
' {$PBASIC 2.5}
'
' =========================================================================
' data, messages in eeprom
msg0 DATA @0,(75) ' reserve space for user message
msg1 DATA "The quick brown fox jumpted over the lazy dog.",0
msg2 DATA "This is a switch because we are reading sentences right out of EPROM!",0
msg3 DATA "Not even Houdini could escape If he were alive.",0
msg4 DATA "Back to the future is a great movie one the whole family will enjoy you must see it soon.",0
msg5 DATA "Now is the Time for all good men to come to the aid of the Party!",0
ReturnPointerTop CON 62 ' will be initial value of stack pointer
ParmPointerTop CON 52 ' will be initial value of Parm pointer
' variable assignments
DataPointer VAR Word ' Used as an address pointer for DATA statements
ReturnPointer VAR Byte ' stack pointer--do not use for anything else!
ParmPointer VAR Byte ' Parm pointer--do not use for anything else!
GoToX VAR Byte ' for bank switching
GoToSlot VAR GoToX.nib1 ' target bank for RUN
GoToLabel VAR GoToX.nib0 ' target routine from BRANCH within bank
cat VAR GoToX ' this byte can be reused within bank
char VAR Byte ' for demo, preserved across banks
' an index for the message to retrieve
temp VAR Byte
temp2 VAR Byte
' --- crossbank labels targets ----
xInit CON $00 ' bank 0 targets
xEnterMessage CON $01
xShowMessage CON $02
xFinal CON $03
xDispMsg CON $10 ' bank 1 targets
xDispMsg1 CON $11
xGetMsgNum CON $12
xPrintEEDATA CON $21 ' bank 2 targets
'#DEFINE DebugMode 'Follow along on the console
' ----------------------------------------------------
' --- top of program
BRANCH GoToLabel,[Init,printEEDATA]
Init:
DEBUG "Stoping at Slot 2 Init.",CR
STOP
printEEDATA:
GET ParmPointer,char : ParmPointer=ParmPointer+1 ' retrieve (pop) the Var we need
#IF DebugMode #THEN DEBUG "We are in printEEData subroutine printing message# ", DEC1 char, ".",CR #ENDIF
STORE 2 ' now look at data in the next slot
LOOKUP char,[msg0,msg1,msg2,msg3,msg4,msg5],DataPointer ' map to message start address
char = " " ' else first character would be a 0 and erase screen
DO
DEBUG char
READ DataPointer,char
DataPointer=DataPointer+1
LOOP WHILE char
DEBUG CR
GET ReturnPointer,GoToX : ReturnPointer=ReturnPointer+1 ' get (pop) the return vector
#IF DebugMode #THEN DEBUG CR,"GoTo is Now=", HEX2 GoToX, " ReturnPointer=", SDEC ReturnPointer - ReturnPointerTop, ".",CR #ENDIF
RUN GoToSlot ' GoTo back to target

Comments
I never got around to a full stack implementation, thinking it too cumbersome and unnecessary for my purposes. My stack was only one level deep, so its fixed return pointer location in scratchpad memory I named "back", not "stack". An early version of my implementation is still up on my website at http://emesystems.com/OLDSITE/BS2SX.htm#Crossbank.
It is interesting to see how you have made a deeper stack. 10 deep, right? Why top at location 62?
One comment. Since the Stamp assigns space in RAM in order of words, bytes, nibs, bits, I found it important to assign my cross-bank variable to the first word in all the linked programs. Same goes for shared flags and other template variables. Doing so allows new code to be added in any slot independently without worrying about bumping the position of the critical template variables.
back CON 126 ' single level stack, one fixed loc, the last in scratchpad ram ' return target for crossbank calls in BS2pe, BS2P, BS2px ' PUT the return target here, GET it from here to return or chain. wsx VAR Word ' always the first declared word in every bank lola VAR wsx.BYTE0 ' alias inside wsx, this is the branch variable, has two components lolarun VAR lola.NIB1 ' alias inside lola, which slot to run, RUN lolarun lolago VAR lola.NIB0 ' alias inside lola, one of 16 possible routines to run in the target slot cat VAR lola ' sometimes I want to use the lola variable for something other than a cross-slot jump dog VAR wsx.BYTE1 ' sometimes this passes data direct or as pointer, otherwise general purpose.The variable name lola is a tribute to the main character in the 1999 crime action drama, Run Lola Run.62 was just random! and when you want to make changes with slots you have to do it in so many places. Just adding a slot label to jump to and answering a distracting phone call can create debugging problems later. 52 is the start of the data stack, thinking who would ever need a return stack that deep on a stamp.
I agree with you on the assignment, but I have another plan, another slot version and perhaps you were the origin of this as well. When switching Slots save all the variables and restore when you land in the new slot. On a BS2p and up you can save all 26 word vars x4 with 24 scratchpad bytes to spare. So the stacks can not be so big. My goal is to combine the two Slot systems without making it an impossible monster to work with. Maybe the top 2-3 word vars would not have to be saved since they are the same anyway
Here is the Part of the non-stack version showing the Save and restore vars at the bottom
' ========================================================================= ' ' File...... Master.bpx ' Purpose... Program for slot demo showing local and shared variables. ' ' Author.... TimC. (based on code from Chris Anderson, Tracy Allen and Parallax) ' E-mail.... ' Started... 30 Mar 2020 ' Updated... ' Tim Comments... Working ' ' {$STAMP BS2p, slot1, slot2, slot3} ' {$PBASIC 2.5} ' ' ========================================================================= ' -----[ Program Description ]--------------------------------------------- ' 'This Slot demo uses a BS2p to show how to use slots to add more code space and more ram space. 'By using the scratchpad memory real local variables and shared variables can be created. 'At a minimum each Slot uses about 256 bytes of program storage and 1 Word of Ram to operate this way 'The ramaining space in each slot is available for your app. The BS2e and BS2sx have less 'scratchpad memory so only 2 slots of local memory can be saved. Larger chips like the BS2p 'are allowed 3 slots of local memory as seen in this example. 'There is one example in Slot 1 Label 3 of calling another routine in slot 3 and then 'returning to Slot 1 which then returns to the Master Slot. Since there is no stack 'Doing and more sub calling would get messy fast. 'Now it will be easier to write you apps with 20 bytes of variables per slot and '1 3/4K per slot to work with. ' -----[ I/O Definitions ]------------------------------------------------- LCD PIN 9 ' Simple serial LCD display E PIN 0 ' connect LCD to OutL (Jumper JU3 must be installed) ' -----[ Constants ]------------------------------------------------------- ' PgmSlotC CON 0 ' Edit Here. With the Program Slot Number LastSlot CON 0 ' Edit Here. Change to 1 if this is the last Slot Number #SELECT $STAMP #CASE BS2E, BS2SX BankVarsStart CON 11 'Edit Here BS2SX and above Main=11, Slot1=37, Slot3=200 (error) #CASE BS2P, BS2PE, BS2PX BankVarsStart CON 23 'Edit Here BS2p and above Main=23, Slot1=49, Slot2=75, Slot3=101, Slot4=200 (error) #CASE #ELSE #ERROR "Stamp Chip not defined for Slots programing." #ENDSELECT 'Common LCD codes LCD_CMD CON 254 LCD_CLEAR CON 1 LCD_HOME CON 2 LCD_LINE1 CON $80 LCD_LINE2 CON $C0 LCD_DEG CON 223 ' For Temperature Readings 'Common Debug Window codes DBG_CLEAR CON 0 DBG_HOME CON 1 DBG_BELL CON 7 DBG_CURSORXY CON 2 DBG_TAB CON 9 DBG_CLEARDOWN CON 12 DBG_DEG CON 223 ' For Temperature Readings 'Handy On Off, Yes No Constants LedOn CON 1 ' LED is driven High LedOff CON 0 ' LED Pin is Low isOn CON 1 ' LED is active high isOff CON 0 ' LED Pin is low Ack CON 0 NoAck CON 1 No CON 0 Yes CON 1 ' Baud rate Constant #SELECT $STAMP #CASE BS2PX T38K4 CON 84 ' The smaller parallax display uses this N19K2 CON 188 N9600 CON 396 #CASE BS2P, BS2SX T115K2 CON 2 ' The 140x32 display uses this T38K4 CON 45 ' The smaller parallax display uses this N19K2 CON 110 N9600 CON 240 #CASE BS2, BS2E, BS2PE T38K4 CON 6 N19K2 CON 32 N9600 CON 84 #CASE #ELSE #ERROR "Stamp Chip Baud speed not defined for this program." #ENDSELECT Inverted CON $4000 ' + This for the larger displays. or True = 0 Open CON $8000 ' or Driven = 0 Even CON $2000 ' or No parity = 0 ' Choose Speed Here for easier editing 'Baud CON N9600 ' Use this for TTL Baud CON N9600 + Inverted ' Use this when set for RS232 'Baud CON N19K2 + Inverted ' For Matrix orbital Graphics Display ' ' -----[ Global Variables ]-------------------------------------------------- ' ' Global Variables are locations shared in the ScratchPad ' Max location is 10 for smaller chips and 22 for the larger ' use GET To move To a local variable and PUT after changing to save MainReturnLabelSCR CON 0 ' Location in scratchPad Used by Task 0 ReturnModuleSCR CON 1 ReturnLabelSCR CON 2 SlotLabelSCR CON 3 ' Location in scratchPad Used by Slots to find which task ReturnCodeSCR CON 4 ' -----[ Local Variables ]-------------------------------------------------- ' ' MainReturnLabel VAR Nib ' used by task 0 ReturnModule VAR Nib ReturnLabel VAR Nib SlotLabel VAR Nib ' used by Slots to find which task ReturnCode VAR Nib ' device check return ocde pgmSlot VAR Nib ' what probram slot we are in loaded Via LoadSlotVars rwSlot VAR Nib ' what R/W slot the STORE command is pointing to for the Read/Write cmd zzzVar VAR Byte ' test var temp VAR Byte ' temporary working variables usefull in every slot looper VAR Byte ' temporary working variables usefull in every slot ' -----[ EEPROM Data ]----------------------------------------------------- ' ' -----[ Initialization ]-------------------------------------------------- ' GOSUB RecallVars 'testing this mod PUT ReturnModuleSCR, 0 ' Main module is never a subroutine to a slot GET MainReturnLabelSCR, MainReturnLabel ' casting a byte to a nib works without spilover :) GET SlotLabelSCR, SlotLabel ' For Documentation to say where we have been BRANCH MainReturnLabel, [init, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14] 'Reentry index matches label # init: 'This only happends once! Last slot will INC MainReturnLabel DEBUG DBG_CLEAR,"Starting MultiSlot program.",CR, "Running Init: " GOTO InitAllSlots 'Yup a goto, not clean programming but necessary returns to _1: below DEBUG "At bottom of Init all slots in Main Module, We should never be here!", CR ' -----[ Program Code ]---------------------------------------------------- ' _1: ' Return here from Init of all slots. ' Slot 1, SlotLabel 1, Return here to _2: (MainReturnLabelSCR will match return label number) PUT SlotLabelSCR, 1 : PUT MainReturnLabelSCR, 2 : GOSUB SaveVars : RUN 1 : _2: DEBUG "*#1 RETURN FROM Run 1 SlotLabel ", DEC SlotLabel," *",CR 'DEBUG "zzzVar=", SDEC zzzVar ,CR ' Slot 1, SlotLabel 1, Return here to _3: (MainReturnLabelSCR will match return label number) PUT SlotLabelSCR, 1 : PUT MainReturnLabelSCR, 3 : GOSUB SaveVars : RUN 1 : _3: DEBUG "*#2 RETURN FROM Run 1 SlotLabel ", DEC SlotLabel," *",CR 'DEBUG "zzzVar=", SDEC zzzVar ,CR ' Slot 2, SlotLabel 1, Return here to _4: (MainReturnLabelSCR will match return label number) PUT SlotLabelSCR, 1 : PUT MainReturnLabelSCR, 4 : GOSUB SaveVars : RUN 2 : _4: DEBUG "*#3 RETURN FROM Run 2 SlotLabel ", DEC SlotLabel," *",CR ' Slot 2, SlotLabel 2, Return here to _5: (MainReturnLabelSCR will match return label number) PUT SlotLabelSCR, 2 : PUT MainReturnLabelSCR, 5 : GOSUB SaveVars : RUN 2 : _5: DEBUG "*#4 RETURN FROM Run 2 SlotLabel ", DEC SlotLabel," *",CR ' Slot 1, SlotLabel 2, Return here to _6: (MainReturnLabelSCR will match return label number) PUT SlotLabelSCR, 2 : PUT MainReturnLabelSCR, 6 : GOSUB SaveVars : RUN 1 : _6: DEBUG "*#5 RETURN FROM Run 1 SlotLabel ", DEC SlotLabel," *",CR LCDOUT E, LCD_Line1, ["SlotsAre"] ' easy banner LCDOUT E, LCD_Line2, [" Great! "] ' Slot 3, SlotLabel 1, Return here to _7: (MainReturnLabelSCR will match return label number) PUT SlotLabelSCR, 1 : PUT MainReturnLabelSCR, 7 : GOSUB SaveVars : RUN 3 : _7: DEBUG "*#6 RETURN FROM Run 3 SlotLabel ", DEC SlotLabel," *",CR ' Slot 1, SlotLabel 3, Return here to _8: (MainReturnLabelSCR will match return label number) PUT SlotLabelSCR, 3 : PUT MainReturnLabelSCR, 8 : GOSUB SaveVars : RUN 1 : _8: DEBUG "*#7 RETURN FROM Run 1 SlotLabel ", DEC SlotLabel," *",CR DEBUG "zzzVar=", SDEC zzzVar ,CR, "--Fini--", CR 'PAUSE 60000 'GOTO start ' Remove labels from this list after using in routines _9: _10: _11: _12: _13: _14: END ' -----[ Subroutine Section ]----------------------------------------------------- InitAllSlots: GOSUB LoadSlotVars ' where are we variable zzzVar = pgmSlot+99 ' sample variable to confirm values are saved DEBUG DEC pgmSlot, ", " GOSUB SaveVars : RUN pgmSlot+1 DEBUG "At bottom of Init all slots in Main Module, We should never be here!", CR LoadSlotVars: ' We dont need to run this if we use a constant in each slot and dont need rwslot #SELECT $STAMP #CASE BS2 pgmSlot = 0 ' everything in slot 0 rwSlot = 0 #ERROR "Stamp Chip not defined for Slots programing." #CASE BS2E, BS2SX GET 63, temp ' read current slot rwSlot = temp.highnib ' READ/WRITE slot is same #CASE BS2P, BS2PE, BS2PX GET 127, temp ' get slot control byte rwSlot = temp.nib1 ' READ/WRITE in high nibble pgmSlot = temp.nib0 ' pgm slot in low nibble #ENDSELECT RETURN ' BS2sx 26x2 = 52 which leaves 12 scratchpad bytes 0-11 ' BS2p and above 26x4 = 104 leaves 24 scratchpad bytes 0-23 'Save All 26 Variables, can support main plus 3 slots SaveVars: 'Increase the save pointer when we are in a higher bank 'BankVarsStart = BankVarsStart + (26 * pgmSlot) 'First save the one we will destroy PUT (BankVarsStart + 25), B0(25) FOR B25 = 0 TO 24 PUT (BankVarsStart + B25), B0(B25) NEXT RETURN 'Restore All 26 Variables, can support main plus 3 slots RecallVars: 'Increase the restore pointer when we are in a higher bank 'BankVarsStart = BankVarsStart + (26 * pgmSlot) 'First save the one we will destroy GET (BankVarsStart + 25), B0(25) FOR B25 = 0 TO 24 GET (BankVarsStart + B25), B0(B25) NEXT RETURNhttps://www.parallax.com/downloads/nuts-volts-stamp-applications-87-multi-bank-programming
Toward the end of the article Jon suggests an approach where the main program would PUT all of the RAM variables into the scratchpad, saving them, like on a stack, for later retrieval with GETs. His example earlier in that article didn't do that; used a more ad-hoc approach instead.
I found this example from Chris Anderson. I forget what sort of applications he had.
https://forums.parallax.com/discussion/comment/504138
My own apps needed something KISS, fast and systematic. I used my template for over 1000 programs, mostly variations on a Stamp2pe platform that had data storage with the option of eeprom, flash, or FTDI vDrive, also included a small amount of battery backed ram in the RTC chip to survive Stamp reset. There were options for lots of sensors and some effectors, communications by cable or wireless. Usually 6 to 8 slots in use, and almost all of the scratchpad memory was commandeered for data and computation buffers.
About the number 62, I couldn't place why it looked so familiar. That is the top scratchpad memory address in the .bsx and .bse. The later Stamps, p, pe and px had more, top address 126.
I have the merged code working.
So now I get 20 free bytes of local storage per slot, 10 Bytes of stack space and 10 bytes of Scratch space left over.
Going to any slot routine is easier:
GoToX = x13SimpleMessage : PUT ReturnPointer,x05RecordData : GOTO SlotGo ' The simpleist example. No parms passed
And with a parm:
char = 55 'just something to pass
PUT ParmPointer,char : ParmPointer=ParmPointer-1 ' put the parameter char on the stack then dec
GoToX = x11ProcessData : PUT ReturnPointer,x02ReadTemperature : GOTO SlotGo ' Where to go, Where to return, GO!
A slot subroutine starts with it's label and now only needs a goto
_13SimpleMessage:
DEBUG "In Slot ", DEC pgmSlot, " Label ", DEC GoToLabel, CR
GOTO SlotReturn
The idea that Jon William's had of saving RAM variables into the scratchpad is working as well:
SaveVars:
'Decrease the save pointer when we are in a higher bank
'First save B5, the one we will destroy
PUT BankVarsStart, B0(5)
FOR B5 = 6 TO 25
PUT (BankVarsStart + B5 - 5), B0(B5)
NEXT
'Finally restore B5
GET BankVarsStart, B0(5)
RETURN
I still have a lot more work to do before it can be looked at so maybe a few more days.
Regards
Tim
Here is the new version I promised.
Cleaned up some errors with edge cases saving and restoring local variables. The 2 stacks are better managed. I have left in place lots of debug statements just in case things go wrong. 2 bytes of global ram (Global X, GlobalY and GlobalbitQ) are available for your use as well. Added one more trick that might be useful:
_2: ' LCDInit ' This is a dual use Routine either called from another module OR as a standard subroutine ' within the module. Remember to set Flag isSubroutine if within module. NAP 5 ' let LCD self-initialize DIRL = %11111110 ' setup pins for LCD LCDCMD E, %00110000 : PAUSE 5 ' 8-bit mode LCDCMD E, %00110000 : PAUSE 0 LCDCMD E, %00110000 : PAUSE 0 LCDCMD E, %00100000 : PAUSE 0 ' 4-bit mode LCDCMD E, %00101000 : PAUSE 0 ' multi-line mode LCDCMD E, %00001100 : PAUSE 0 ' no crsr, no blink LCDCMD E, %00000110 ' inc crsr, no disp shift LCDCMD E, LCD_CLEAR ' blank screen, home cursor 'Remove next 3 lines after testing LCDOUT E, LCD_Line1, ["Hanging "] ' easy banner LCDOUT E, LCD_Line2, ["in Slot1"] PAUSE 9000 ' Need to pause to see LCD. IF isSubroutine THEN RETURN GOTO SlotReturnIt's a subroutine that acts like any other subroutine when the isSubroutine bit set. When running from another slot it will return control back to the caller in any other slot. No Hard coding slot numbers. isSubroutine is cleared automatically when jumping to another slot.
Have fun
Tim
The 3 files Below are: Master 0, Slot 1, Slot 2.