Shop OBEX P1 Docs P2 Docs Learn Events
Beginner with BS2SX — Parallax Forums

Beginner with BS2SX

ArchiverArchiver Posts: 46,084
edited 2001-12-26 20:21 in General Discussion
I wrote a program for a BS2, but there is not enough space. So I got
a BS2SX because it has more EEPROM space. When I tried to download
the program to the BS2SX (using the same carrier board), the editor
still said, "EEPROM Full." I changed the setting in the Preferences,
Editor Operation menu to BS2SX, and it still won't work. Does anyone
know how to fix this problem? Thanks.

Comments

  • ArchiverArchiver Posts: 46,084
    edited 2001-12-25 14:57
    I would suspect that you exceeded the 2k by 8 page limit on the SX.
    You have 16K bytes (program and data in 8 x 2K program spaces) on the SX.
    You need to organize your program to fit within 2k pages.
    Another possiblity is your variable storage space exceeded the maximum
    available.


    Original Message
    From: sethjaredjeromiejohnson [noparse]/noparse]mailto:[url=http://forums.parallaxinc.com/group/basicstamps/post?postID=gm8PgM5dlY85Xv6YoASg-8qy1JRlkMkjVFJbE8JW2osN9pW-oC4BKFPiw_8PgASmBFGulOi5mKernrO99mc]sjohns10@h...[/url
    Sent: Tuesday, December 25, 2001 8:29 AM
    To: basicstamps@yahoogroups.com
    Subject: [noparse][[/noparse]basicstamps] Beginner with BS2SX


    I wrote a program for a BS2, but there is not enough space. So I got
    a BS2SX because it has more EEPROM space. When I tried to download
    the program to the BS2SX (using the same carrier board), the editor
    still said, "EEPROM Full." I changed the setting in the Preferences,
    Editor Operation menu to BS2SX, and it still won't work. Does anyone
    know how to fix this problem? Thanks.


    To UNSUBSCRIBE, just send mail to:
    basicstamps-unsubscribe@yahoogroups.com
    from the same email address that you subscribed. Text in the Subject and
    Body of the message will be ignored.


    Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-25 15:02
    In a message dated 12/25/01 8:30:21 AM Central Standard Time,
    sjohns10@h... writes:


    > I wrote a program for a BS2, but there is not enough space. So I got
    > a BS2SX because it has more EEPROM space. When I tried to download
    > the program to the BS2SX (using the same carrier board), the editor
    > still said, "EEPROM Full." I changed the setting in the Preferences,
    > Editor Operation menu to BS2SX, and it still won't work. Does anyone
    > know how to fix this problem? Thanks.

    The BS2sx has eight, 2 kByte program slots. What you need to do is pull
    portions out of your main program and put them into another program slot. If
    your variable definitions are the same in both programs, they will be
    preserved when you use the RUN command. Otherwise, you can use PUT to store
    values in the SPRAM and GET to retrieve them when you've changed program
    slots.

    -- Jon Williams
    -- Parallax


    [noparse][[/noparse]Non-text portions of this message have been removed]
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-25 23:57
    I got the program into three seperate slots, but whenever I try to
    compile it, it comes up with an "Undefined Label" error in the
    second slot where there is a gosub instruction. The gosub
    instruction in the second slot tells the program to go back to the
    first slot, then return. How would I fix this? Thanks.
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-25 23:57
    I got the program into three seperate slots, but whenever I try to
    compile it, it comes up with an "Undefined Label" error in the
    second slot where there is a gosub instruction. The gosub
    instruction in the second slot tells the program to go back to the
    first slot, then return. How would I fix this? Thanks.
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-26 02:00
    --- In basicstamps@y..., "peter verkaik" <peterverkaik@b...> wrote:
    > Hi,
    >
    > The easiest way is to copy the subroutine in the first slot
    > to the second slot. Place a remark by both the subroutines
    > that there is a copy of this routine in an other slot.
    > This will remind you later to change both subroutines
    > iIf they need to be modified.
    > There are pitfalls though, for example, variables used in the
    > subroutine must also be available in the slot you
    > copy the routine to.
    >
    > Regards peter

    Almost every section of my program is dependant on another section in
    the program. For instance, I have the program going back to the
    beginning often to check the state of the power button. There are
    several instances similar to that one, and if I copied them all to
    where they were needed (in the same slot), then I'm back to start
    because the program is too large to fit in one slot. Is there some
    way to get the program to recognize that the other parts of the
    program are in different slots? Thank you very much for your help.
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-26 03:26
    GOSUB only works within the program slot you are in. The RUN command is used
    to switch between program slots, and then it always begins at the first
    line.

    Original Message


    > I got the program into three seperate slots, but whenever I try to
    > compile it, it comes up with an "Undefined Label" error in the
    > second slot where there is a gosub instruction. The gosub
    > instruction in the second slot tells the program to go back to the
    > first slot, then return. How would I fix this? Thanks.
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-26 05:05
    Whoops you are right. I'll fix it shortly. Sorry!

    Al Williams
    AWC
    * Floating point math for the Stamp, PIC, SX, or any microcontroller
    http://www.al-williams.com/awce/pak1.htm



    >
    Original Message
    > From: peter verkaik [noparse]/noparse]mailto:[url=http://forums.parallaxinc.com/group/basicstamps/post?postID=xSQvJ3Y5HOmzI7tnBHBulBsuxwW-RB6dSPiv6mQuIyYNShOJf0gmYDt_Z72OPgPeMkuIGSFqYWE5ujU0ttAlO2t5shc]peterverkaik@b...[/url
    > Sent: Wednesday, December 26, 2001 7:33 AM
    > To: basicstamps@yahoogroups.com
    > Subject: RE: [noparse][[/noparse]basicstamps] Re: Beginner with BS2SX
    >
    >
    > Hi,
    >
    > I noticed Al's faq page has a disturbed pagelayout concerning
    > the example. So here is the original from my archive.
    >
    > Multilevel stack design and usage for Basic Stamp BS2SX, BS2E
    > and BS2P using the scratchpad.
    >
    > Many thanks to Tracy Allen for all his input and positive suggestions.
    >
    > This design uses the available scratchpad to hold a
    > multilevel stack that can be used to call functions (with
    > parameters if required) in other programs and to create named
    > local variables for use within gosubs. It shows a general
    > program setup that can be used as a template.
    >
    > Features:
    > up to 32 entry/return points per program
    > nested program calls
    > parameter passing via stack
    > named local variables for subroutines
    >
    > Limitations:
    > program calls can only execute at main level code outside
    > for-next loops. names for local variables must be unique as
    > they are seen as aliases no stackpointer check
    >
    > 'scratchpad usage (TOS stands for Top Of Stack)
    > 'TOS-0 = entryID/runID 1
    > 'TOS-1 = entryID/runID 2
    > 'TOS-2 = entryID/runID 3
    > 'etc.
    >
    > 'program 0
    >
    > TopOfStack1 con 62 'top of stack
    > fot BS2SX, BS2E
    > TopOfStack2 con 126 'top of stack for BS2P
    >
    > TOS con TopOfStack2 'pick the right
    > top of stack
    > STACKSIZE con 30 'define stacksize
    > BOS con TOS-STACKSIZE 'bottom of stack
    >
    > EN1P0 con (1<<3)+0 'entry01 in program 0
    > EN2P0 con (2<<3)+0 'entry02 in program 0
    > EN3P0 con (3<<3)+0 'entry03 in program 0
    > EN4P0 con (4<<3)+0 'entry04 in program 0
    > EN5P0 con (5<<3)+0 'entry05 in program 0
    > EN4P3 con (4<<3)+4 'entry 4 in program 3
    > EN14P4 con (14<<3)+4 'entry
    > 14 in program 4
    > EN6P7 con (6<<3)+7 'entry 6 in program 7
    >
    > 'system variables
    > TargetID var byte 'entry index
    > and program to run
    > runID var TargetID.lownib 'entry index
    > b0, program to run
    > entryID var TargetID.highnib 'entry
    > index b4-b1
    > StackPointer var byte 'stackpointer
    >
    > 'application variables
    > x var byte
    > y var byte
    > z var byte
    >
    > ProgramID con 0
    >
    > begin0:
    > branch
    > (TargetID>>3),[noparse][[/noparse]main0,entry01,netry02,...,entry1F]'first entry
    > for direct run
    >
    > main0:
    > StackPointer=TOS
    > 'insert init code here
    >
    > main0loop:
    > 'insert mainloop code here
    >
    > z=0
    > call_loop_example:
    > '1st program call example, stackpointer check could be
    > placed here
    > put StackPointer,EN1P0
    > StackPointer=StackPointer-1
    > TargetID=EN14P4
    > run TargetID 'execute entry 14 in program 4, then
    > return to entry01
    > entry01:
    > 'return point for call
    > z=z+1
    > if z<10 then call_loop_example
    >
    > 'insert mainloop code here
    >
    > '2nd call example, stackpointer check could be placed here
    > put StackPointer,x 'first put parameters onto stack
    > put StackPointer-1,y
    > put StackPointer-2,EN2P0 'then put return point
    > StackPointer=StackPointer-3
    > TargetID=EN6P7
    > run TargetID 'execute entry 6 in program 7, then
    > return to entry01
    > entry02:
    > 'return point for call
    > get StackPointer+2,x 'retrieve results
    > get StackPointer+1,y
    > StackPointer=StackPointer+2 'remove results from stack
    >
    > 'insert mainloop code here
    >
    > 'direct run example
    > TargetID=$03
    > run TargetID 'run program 3 directly (no call but jump)
    >
    > 'insert mainloop code here
    >
    > main0end:
    > goto main0loop
    >
    > 'function entries for program calls
    >
    > entry03:
    > gosub function_03
    > put StackPointer,EN4P3
    > StackPointer=StackPointer-1
    > TargetID=EN4P0
    > run TargetID 'execute entry 14 in program 4, then
    > return to entry01
    > entry04:
    > 'return point for call
    > goto ReturnFromProgramCall_0
    >
    > entry05:
    > get StackPointer+3,x 'get parameters from stack
    > get StackPointer+2,y
    > gosub function_04 'perform some math on x and y,
    > results in x and y
    > put StackPointer+3,x 'place results on stack
    > put StackPointer+2,y
    > goto ReturnFromProgramCall_0
    >
    > ReturnFromProgramCall_0:
    > StackPointer=StackPointer+1 'adjust stack here
    > get StackPointer,TargetID 'get TargetID
    > run TargetID 'return to parent program
    >
    > 'subroutines
    >
    > function_03:
    > gosub alloc4 'allocate 4 bytes for local variables
    > x1 var W12 'local word variable
    > y1 var B23 'local byte variable
    > 'code here
    > goto free4 'free local variables and return from gosub
    >
    > function_04:
    > 'code here
    > return
    >
    > alloc8: put StackPointer,B18 'space is
    > allocated from B25 upwards
    > put StackPointer-1,B19
    > put StackPointer-2,B20
    > put StackPointer-3,B21
    > StackPointer=StackPointer-4
    > alloc4: put StackPointer,B22
    > put StackPointer-1,B23
    > put StackPointer-2,B24
    > put StackPointer-3,B25
    > StackPointer=StackPointer-4
    > return
    >
    > free8: get StackPointer+8,B18
    > get StackPointer+7,B19
    > get StackPointer+6,B20
    > get StackPointer+5,B21
    > get StackPointer+4,B22
    > get StackPointer+3,B23
    > get StackPointer+2,B24
    > get StackPointer+1,B25
    > StackPointer=StackPointer+8
    > return
    >
    > free4: get StackPointer+4,B22
    > get StackPointer+3,B23
    > get StackPointer+2,B24
    > get StackPointer+1,B25
    > StackPointer=StackPointer+4
    > return
    >
    > end
    >
    >
    > When we use the stack for program calls, each program should
    > start with a branch statement as shown in program 0. The
    > first entry for all these branch statements must point to the
    > program's main entry. The reamaining entries (max. 31) point
    > to either function entries or call return points. The global
    > variable TargetID holds the index for the branch statements
    > in its upper five bits. The lower three bits of TargetID
    > determine the program to run.
    >
    > At powerup/rest all variables are cleared to 0, so TargetID
    > holds 0, and therefore the brach statement takes us to main0.
    > At that point the stackpointer is initialized. This stack
    > initialization is only required at this point in program 0.
    > The other programs do not require such an initialization.
    >
    > Now take a look at the call_loop_example. It demonstrates how
    > to do program calls inside a loop. Remember you can not use
    > for-next loops, hence the if-then construction that simulates
    > a for-next loop without using the Stamp internal stack which
    > is reset when switching programs. To do a program call, you
    > must first save the return point onto the stack. The statements
    >
    > put StackPointer,EN1P0
    > StackPointer=StackPointer-1
    >
    > handle this. The constant EN1P0 is calculated at compile-time
    > and is determined by the index of entry01 in the branch
    > statement and the program the call is made from. The statement
    >
    > TargetID=EN14P4
    >
    > is used to set the target, i.e the function entry point
    > inside the program we want to call. The statement
    >
    > run TargetID 'execute entry 14 in program 4, then
    > return to entry01
    >
    > will then switch to the program determined by the three lower
    > bits of TargetID. The first line of code for this new program
    > holds a simular branch statement as shown above. Given
    > TargetID, the branch statement takes us to the desired
    > function entry, which is simular to entry03 in the above
    > example. The function itself is programmed as a subroutine
    > that is called from this entry. Upon return from this
    > subroutine the function first performs another program call
    > (we now have two nested program calls) and then exits by
    > going to the ReturnFromProgrammCall entry. The number of
    > nested program calls allowed is determined by the available
    > stackspace. The statements
    >
    > StackPointer=StackPointer+1 'adjust stack here
    > get StackPointer,TargetID 'get TargetID
    >
    > get the stored return point from the stack. The statement
    >
    > run TargetID 'return to parent program
    >
    > then switches back to the parent program that made the call,
    > and via the brach statement the program continues at label
    > entry01, the entry we had to return to. A special note on the
    > loop variable z in the above example: for the loop to work
    > this variable must not be changed by the called program, so
    > be aware of any aliases. Note the absence of any stack
    > overflow or underflow. You could place a test statement like
    >
    > if StackPointer-'required bytes' < BOS then 'do no call'
    >
    > before each call but this gives much overhead and interferes
    > with the program flow. It is best to keep track of the
    > necessary stack space during programming and selecting a
    > STACKSIZE value that is slightly larger. Also note that the
    > BOS constant determines the maximum number of bytes that can
    > be read into the scratchpad using the SERIN command, without
    > conflicting with the stack. At any time, the StackPointer
    > variable determines the absolute maximum number of bytes to
    > read in with SERIN, without corrupting the stack.
    >
    > To demonstrate passing variables via the stack take a look at
    > the second call example. Here any parameters are placed onto
    > the stack prior to the return point. Also note how the
    > stackpointer is adjusted. The function to call is simular to
    > entry05. This function retrieves the parameters into named
    > variables to allow math calculations before calling the
    > actual function, which again is programmed as a subroutine.
    > Upon return from this subroutine, any results (if any, or
    > maybe in other variables) are placed back onto the stack to
    > the locations occupied by the parameters. If the total bytes
    > of any result is more than the total bytes of the parameters,
    > you should have reserved this space by decreasing the
    > stackpointer more, prior to calling. At all times however,
    > the return point is the last byte on the stack. Once we are
    > back at the return point, any result is retrieved from the
    > stack and the stackpointer is adjusted.
    >
    > Why passing variables via the stack if we can use variables?
    >
    > Whenever possible, the use of variables is the way to go.
    > This scheme of 'call by reference' takes less time and less
    > code. It has a major drawback: the function cannot call
    > itself. By using the stack for parameter passing, we use a
    > scheme known as 'call by value' which does allow a function
    > to call itself (recursive programming). Why would we want this?
    >
    > Lets take the example of the faculty calculation y=x! (for
    > x=6 then 6!=1*2*3*4*5*6), which is not the best example as it
    > can easily be program with a for-next loop, but it
    > demonstrates recursive programming.
    >
    > unsigned integer faculty(unsigned integer x)
    > {
    > if x=0 then return 1 else return x*faculty(x-1)
    > }
    >
    > For x=6 the function calls itself six times. The final result
    > is 1*1*2*3*4*5*6. Note that the factor 1 occurs twice, once
    > for faculty(0) and once for faculty(1). Also note there
    > always must be a limiting factor, in this case the function
    > stops calling itself when x=0. Whenever possible you should
    > try to avoid recursive programming as it requires lots of
    > stackspace which may not be available, resulting in program
    > errors. It's nice to have the option though. In the function
    > above no additional variables were required. If they are,
    > they have to created onto the stack (local variables), and
    > any results for these variables have to be writtrn to the
    > stack prior to the function calling itself. Each time the
    > function calls itself, a new set of local variables is
    > created onto the stack. This makes the function re-entrant,
    > which is imperative for recursive programming.
    >
    > Unfortunately, variables on the stack are not easy to use.
    > You can not directly use them for calculations or testing, so
    > a great number of put and get commands would be required
    > within each function. To reduce the overhead we work the
    > other way around. We save the last piece of variable ram onto
    > the stack and define new variables occupying this ram space.
    > Take a look at function_03 for an example.
    >
    > function_03:
    > gosub alloc4 'allocate 4 bytes for local variables
    > x1 var W12 'local word variable
    > y1 var B23 'local byte variable
    > 'code here
    > goto free4 'free local variables and return from gosub
    >
    > The alloc subroutines copy the contents of the last 4 or 8
    > bytes of variable ram to the stack. To reduce code only 4 or
    > 8 bytes can be freed, which is enough for most cases. See how
    > the local variables x1 and y1 are defined to known locations
    > inside the freed variable ram. To keep things clear, you
    > should use these variables only within the subroutines in
    > which they are defined (for for-next loops, counters,
    > intermediate results etc.), because for the stamp compiler
    > they are just aliases. Upon return from the subroutine you
    > must go to either free4 (if you used alloc4) or free8 (if you
    > used alloc8) to restore the contents of the variable ram. In
    > this way we only have two statements overhead and direct
    > access to the local variables. The same technique is
    > applicable to program calls. The main advantages of these
    > local variables is that you can avoid running out of variable
    > space (using variables for multiple purposes which may lead
    > to hard to debug errors) and making functions re-entrant.
    >
    > This concludes this article about stack use for the stamp.
    > I hope it demonstrates the program power that a multilevel
    > stack can provide.
    >
    > Peter Verkaik, May 14, 2001
    > Any more suggestions are welcome.
    > Please send errors, enhancements and suggestions to
    > peterverkaik@e...
    >
    > SUPPLEMENT:
    >
    > I ran into the problem of retaining variable values during
    > program switching. Thought you might be interested in my
    > solution. As the stack mechanism does provide a means to
    > retain variable values for the calling program (i.e parent),
    > it does not for the called program (i.e. child), as the ram
    > locations are restored upon return. To overcome this I found
    > an elegant way. I reserve some scratchpad locations above the
    > stack to hold program variables that have to be retained
    > during a program call. Upon entry of a program these values
    > are restored, while when doing a program call these values
    > are saved. This reduces overhead to just 2 gosubs and 2 small
    > routines.
    >
    > Retain1 var word 'retainable vars (known to
    > program only)
    > start at ramlocation 0
    > '
    > Global1 var word 'globals (known to all programs)
    > '
    > Local1 var word 'locals stop at ramlocation
    > 25 (known to
    > program only)
    >
    > 'program 0
    >
    > gosub Restore0Global 'first line of code: restore
    > context upon entry
    > branch TargetID,[noparse][[/noparse]...]
    > '
    > gosub PushLocal
    > put StackPointer,EN1P0
    > StackPointer=StackPointer-1
    > TargetID=EN6P4
    > goto CallProgram
    > entry01:
    > 'return point
    > gosub PopLocal
    > '
    > CallProgram: 'single entry used for program calling
    > gosub Save0Globsl 'save context before calling
    > run TargetID
    > '
    > '
    > Save0Global:
    > for X=0 to RETAIN0SIZE-1
    > put RETAIN0START-X,B0(X) 'implied array
    > next 'put B0 first,
    > B3 last (for RETAIN0SIZE=4)
    > return
    >
    > Restore0Global:
    > for X=0 to RETAIN0SIZE-1
    > get RETAIN0START-X,B0(X) 'implied array
    > next 'get B0 first,
    > B3 last (for RETAIN0SIZE=4)
    > return
    >
    > 'Program 1
    > Save1Global:
    > for X=0 to RETAIN1SIZE-1
    > put RETAIN1START-X,B0(X) 'implied array
    > next 'put B0 first,
    > B3 last (for RETAIN1SIZE=4)
    > return
    >
    > Restore1Global:
    > for X=0 to RETAIN1SIZE-1
    > get RETAIN1START-X,B0(X) 'implied array
    > next 'get B0 first,
    > B3 last (for RETAIN1SIZE=4)
    > return
    >
    > The constants RETAIN?START and RETAIN?SIZE are defined at the
    > program start.
    > TopOfScratchPad con 126 '126 or 62
    > retain01 var word 'start
    > at ramlocation 0 (program 0)
    > retain02 var byte
    > RETAIN0SIZE con 3
    > RETAIN0START con TopOfScratchPad '126 or 62
    > retain11 var byte 'start
    > at ramlocation 0 (program 1)
    > retain12 var byte
    > RETAIN1SIZE con 2
    > RETAIN1START con RETAIN0START-RETAIN0SIZE
    > etc. until
    > RETAIN7SIZE con 0
    > 'program 7 without retainable variables
    > RETAIN7START con RETAIN6START-RETAIN6SIZE
    > TOS con RETAIN7START-RETAIN7SIZE
    > 'Top Of Stack
    > For programs with a RETAINSIZE=0 the gosub in the first line
    > must be removed, so must the gosub in CallProgram and both
    > routines Save?Global and Restore?Global.
    >
    > Any comments on this procedure for a (stripped down) context
    > switch is welcomed.
    >
    > Regards peter.
    >
    >
    >
    > To UNSUBSCRIBE, just send mail to:
    > basicstamps-unsubscribe@yahoogroups.com
    > from the same email address that you subscribed. Text in the
    > Subject and Body of the message will be ignored.
    >
    >
    > Your use of Yahoo! Groups is subject to
    http://docs.yahoo.com/info/terms/
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-26 10:04
    Hi,

    The easiest way is to copy the subroutine in the first slot
    to the second slot. Place a remark by both the subroutines
    that there is a copy of this routine in an other slot.
    This will remind you later to change both subroutines
    iIf they need to be modified.
    There are pitfalls though, for example, variables used in the
    subroutine must also be available in the slot you
    copy the routine to.

    Regards peter


    Oorspronkelijk bericht
    Van: sethjaredjeromiejohnson [noparse]/noparse]mailto:[url=http://forums.parallaxinc.com/group/basicstamps/post?postID=s8ShSfuAP4EVbbzywxWTAmPqYCI9t_jUBU1ZPGtYB8HagsK5wWuONGB94BZoNFh19MblpgOxcvcPLvMOtzk]sjohns10@h...[/url
    Verzonden: dinsdag 25 december 2001 15:57
    Aan: basicstamps@yahoogroups.com
    Onderwerp: [noparse][[/noparse]basicstamps] Re: Beginner with BS2SX

    I got the program into three seperate slots, but whenever I try to
    compile it, it comes up with an "Undefined Label" error in the
    second slot where there is a gosub instruction. The gosub
    instruction in the second slot tells the program to go back to the
    first slot, then return. How would I fix this? Thanks.


    To UNSUBSCRIBE, just send mail to:
    basicstamps-unsubscribe@yahoogroups.com
    from the same email address that you subscribed. Text in the Subject and
    Body of the message will be ignored.


    Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-26 12:30
    Hi,

    Yes there is a better but more complicated way.
    I once had a discussion with Tracy Allen on this list
    and finally came to a general call/return scheme by
    implenting a stack mechanism using the scratchpad.
    Al Williams has posted the outcome of that discussion at
    http://www.al-williams.com/wd5gnr/stampfaq.htm#s3.20
    (3.20 How can I simulate call/return across banks?)

    Regards peter


    Oorspronkelijk bericht
    Van: sethjaredjeromiejohnson [noparse]/noparse]mailto:[url=http://forums.parallaxinc.com/group/basicstamps/post?postID=5B233YXQ4zSAUslx0gz6hR2GPB_lmrwC732eSEAAzd9PoQ0WZ-OZ0VabpqucekujJrUi8vsjtMX7IgzyQQ]sjohns10@h...[/url
    Verzonden: dinsdag 25 december 2001 18:00
    Aan: basicstamps@yahoogroups.com
    Onderwerp: [noparse][[/noparse]basicstamps] Re: Beginner with BS2SX

    --- In basicstamps@y..., "peter verkaik" <peterverkaik@b...> wrote:
    > Hi,
    >
    > The easiest way is to copy the subroutine in the first slot
    > to the second slot. Place a remark by both the subroutines
    > that there is a copy of this routine in an other slot.
    > This will remind you later to change both subroutines
    > iIf they need to be modified.
    > There are pitfalls though, for example, variables used in the
    > subroutine must also be available in the slot you
    > copy the routine to.
    >
    > Regards peter

    Almost every section of my program is dependant on another section in
    the program. For instance, I have the program going back to the
    beginning often to check the state of the power button. There are
    several instances similar to that one, and if I copied them all to
    where they were needed (in the same slot), then I'm back to start
    because the program is too large to fit in one slot. Is there some
    way to get the program to recognize that the other parts of the
    program are in different slots? Thank you very much for your help.


    To UNSUBSCRIBE, just send mail to:
    basicstamps-unsubscribe@yahoogroups.com
    from the same email address that you subscribed. Text in the Subject and
    Body of the message will be ignored.


    Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-26 13:32
    Hi,

    I noticed Al's faq page has a disturbed pagelayout concerning the example.
    So here is the original from my archive.

    Multilevel stack design and usage for Basic Stamp BS2SX, BS2E and BS2P using
    the scratchpad.

    Many thanks to Tracy Allen for all his input and positive suggestions.

    This design uses the available scratchpad to hold a multilevel stack that
    can be used
    to call functions (with parameters if required) in other programs and to
    create named
    local variables for use within gosubs. It shows a general program setup that
    can be
    used as a template.

    Features:
    up to 32 entry/return points per program
    nested program calls
    parameter passing via stack
    named local variables for subroutines

    Limitations:
    program calls can only execute at main level code outside for-next loops.
    names for local variables must be unique as they are seen as aliases
    no stackpointer check

    'scratchpad usage (TOS stands for Top Of Stack)
    'TOS-0 = entryID/runID 1
    'TOS-1 = entryID/runID 2
    'TOS-2 = entryID/runID 3
    'etc.

    'program 0

    TopOfStack1 con 62 'top of stack fot BS2SX, BS2E
    TopOfStack2 con 126 'top of stack for BS2P

    TOS con TopOfStack2 'pick the right top of stack
    STACKSIZE con 30 'define stacksize
    BOS con TOS-STACKSIZE 'bottom of stack

    EN1P0 con (1<<3)+0 'entry01 in program 0
    EN2P0 con (2<<3)+0 'entry02 in program 0
    EN3P0 con (3<<3)+0 'entry03 in program 0
    EN4P0 con (4<<3)+0 'entry04 in program 0
    EN5P0 con (5<<3)+0 'entry05 in program 0
    EN4P3 con (4<<3)+4 'entry 4 in program 3
    EN14P4 con (14<<3)+4 'entry 14 in program 4
    EN6P7 con (6<<3)+7 'entry 6 in program 7

    'system variables
    TargetID var byte 'entry index and program to run
    runID var TargetID.lownib 'entry index b0, program to run
    entryID var TargetID.highnib 'entry index b4-b1
    StackPointer var byte 'stackpointer

    'application variables
    x var byte
    y var byte
    z var byte

    ProgramID con 0

    begin0:
    branch (TargetID>>3),[noparse][[/noparse]main0,entry01,netry02,...,entry1F]'first entry for
    direct run

    main0:
    StackPointer=TOS
    'insert init code here

    main0loop:
    'insert mainloop code here

    z=0
    call_loop_example:
    '1st program call example, stackpointer check could be placed here
    put StackPointer,EN1P0
    StackPointer=StackPointer-1
    TargetID=EN14P4
    run TargetID 'execute entry 14 in program 4, then return to entry01
    entry01:
    'return point for call
    z=z+1
    if z<10 then call_loop_example

    'insert mainloop code here

    '2nd call example, stackpointer check could be placed here
    put StackPointer,x 'first put parameters onto stack
    put StackPointer-1,y
    put StackPointer-2,EN2P0 'then put return point
    StackPointer=StackPointer-3
    TargetID=EN6P7
    run TargetID 'execute entry 6 in program 7, then return to entry01
    entry02:
    'return point for call
    get StackPointer+2,x 'retrieve results
    get StackPointer+1,y
    StackPointer=StackPointer+2 'remove results from stack

    'insert mainloop code here

    'direct run example
    TargetID=$03
    run TargetID 'run program 3 directly (no call but jump)

    'insert mainloop code here

    main0end:
    goto main0loop

    'function entries for program calls

    entry03:
    gosub function_03
    put StackPointer,EN4P3
    StackPointer=StackPointer-1
    TargetID=EN4P0
    run TargetID 'execute entry 14 in program 4, then return to entry01
    entry04:
    'return point for call
    goto ReturnFromProgramCall_0

    entry05:
    get StackPointer+3,x 'get parameters from stack
    get StackPointer+2,y
    gosub function_04 'perform some math on x and y, results in x and y
    put StackPointer+3,x 'place results on stack
    put StackPointer+2,y
    goto ReturnFromProgramCall_0

    ReturnFromProgramCall_0:
    StackPointer=StackPointer+1 'adjust stack here
    get StackPointer,TargetID 'get TargetID
    run TargetID 'return to parent program

    'subroutines

    function_03:
    gosub alloc4 'allocate 4 bytes for local variables
    x1 var W12 'local word variable
    y1 var B23 'local byte variable
    'code here
    goto free4 'free local variables and return from gosub

    function_04:
    'code here
    return

    alloc8: put StackPointer,B18 'space is allocated from B25 upwards
    put StackPointer-1,B19
    put StackPointer-2,B20
    put StackPointer-3,B21
    StackPointer=StackPointer-4
    alloc4: put StackPointer,B22
    put StackPointer-1,B23
    put StackPointer-2,B24
    put StackPointer-3,B25
    StackPointer=StackPointer-4
    return

    free8: get StackPointer+8,B18
    get StackPointer+7,B19
    get StackPointer+6,B20
    get StackPointer+5,B21
    get StackPointer+4,B22
    get StackPointer+3,B23
    get StackPointer+2,B24
    get StackPointer+1,B25
    StackPointer=StackPointer+8
    return

    free4: get StackPointer+4,B22
    get StackPointer+3,B23
    get StackPointer+2,B24
    get StackPointer+1,B25
    StackPointer=StackPointer+4
    return

    end


    When we use the stack for program calls, each program should start with a
    branch
    statement as shown in program 0. The first entry for all these branch
    statements
    must point to the program's main entry. The reamaining entries (max. 31)
    point
    to either function entries or call return points. The global variable
    TargetID
    holds the index for the branch statements in its upper five bits. The lower
    three
    bits of TargetID determine the program to run.

    At powerup/rest all variables are cleared to 0, so TargetID holds 0, and
    therefore
    the brach statement takes us to main0. At that point the stackpointer is
    initialized.
    This stack initialization is only required at this point in program 0. The
    other programs
    do not require such an initialization.

    Now take a look at the call_loop_example. It demonstrates how to do program
    calls inside
    a loop. Remember you can not use for-next loops, hence the if-then
    construction that simulates
    a for-next loop without using the Stamp internal stack which is reset when
    switching programs.
    To do a program call, you must first save the return point onto the stack.
    The statements

    put StackPointer,EN1P0
    StackPointer=StackPointer-1

    handle this. The constant EN1P0 is calculated at compile-time and is
    determined by the
    index of entry01 in the branch statement and the program the call is made
    from. The statement

    TargetID=EN14P4

    is used to set the target, i.e the function entry point inside the program
    we want to call.
    The statement

    run TargetID 'execute entry 14 in program 4, then return to entry01

    will then switch to the program determined by the three lower bits of
    TargetID.
    The first line of code for this new program holds a simular branch statement
    as shown above.
    Given TargetID, the branch statement takes us to the desired function entry,
    which is
    simular to entry03 in the above example. The function itself is programmed
    as a subroutine
    that is called from this entry. Upon return from this subroutine the
    function first performs
    another program call (we now have two nested program calls) and then exits
    by going to the
    ReturnFromProgrammCall entry. The number of nested program calls allowed is
    determined by
    the available stackspace. The statements

    StackPointer=StackPointer+1 'adjust stack here
    get StackPointer,TargetID 'get TargetID

    get the stored return point from the stack. The statement

    run TargetID 'return to parent program

    then switches back to the parent program that made the call, and via the
    brach statement
    the program continues at label entry01, the entry we had to return to.
    A special note on the loop variable z in the above example: for the loop to
    work this
    variable must not be changed by the called program, so be aware of any
    aliases.
    Note the absence of any stack overflow or underflow. You could place a test
    statement like

    if StackPointer-'required bytes' < BOS then 'do no call'

    before each call but this gives much overhead and interferes with the
    program flow. It is best
    to keep track of the necessary stack space during programming and selecting
    a STACKSIZE value
    that is slightly larger. Also note that the BOS constant determines the
    maximum number
    of bytes that can be read into the scratchpad using the SERIN command,
    without conflicting
    with the stack. At any time, the StackPointer variable determines the
    absolute maximum number
    of bytes to read in with SERIN, without corrupting the stack.

    To demonstrate passing variables via the stack take a look at the second
    call example.
    Here any parameters are placed onto the stack prior to the return point.
    Also note
    how the stackpointer is adjusted. The function to call is simular to
    entry05. This
    function retrieves the parameters into named variables to allow math
    calculations before
    calling the actual function, which again is programmed as a subroutine. Upon
    return
    from this subroutine, any results (if any, or maybe in other variables) are
    placed back
    onto the stack to the locations occupied by the parameters. If the total
    bytes of any
    result is more than the total bytes of the parameters, you should have
    reserved this
    space by decreasing the stackpointer more, prior to calling. At all times
    however, the
    return point is the last byte on the stack.
    Once we are back at the return point, any result is retrieved from the stack
    and the
    stackpointer is adjusted.

    Why passing variables via the stack if we can use variables?

    Whenever possible, the use of variables is the way to go. This scheme of
    'call by reference'
    takes less time and less code. It has a major drawback: the function cannot
    call itself.
    By using the stack for parameter passing, we use a scheme known as 'call by
    value' which does
    allow a function to call itself (recursive programming). Why would we want
    this?

    Lets take the example of the faculty calculation y=x! (for x=6 then
    6!=1*2*3*4*5*6), which is
    not the best example as it can easily be program with a for-next loop, but
    it demonstrates
    recursive programming.

    unsigned integer faculty(unsigned integer x)
    {
    if x=0 then return 1 else return x*faculty(x-1)
    }

    For x=6 the function calls itself six times. The final result is
    1*1*2*3*4*5*6. Note that
    the factor 1 occurs twice, once for faculty(0) and once for faculty(1). Also
    note there
    always must be a limiting factor, in this case the function stops calling
    itself when x=0.
    Whenever possible you should try to avoid recursive programming as it
    requires lots of
    stackspace which may not be available, resulting in program errors. It's
    nice to have
    the option though. In the function above no additional variables were
    required. If they
    are, they have to created onto the stack (local variables), and any results
    for these
    variables have to be writtrn to the stack prior to the function calling
    itself. Each time
    the function calls itself, a new set of local variables is created onto the
    stack.
    This makes the function re-entrant, which is imperative for recursive
    programming.

    Unfortunately, variables on the stack are not easy to use. You can not
    directly use
    them for calculations or testing, so a great number of put and get commands
    would be
    required within each function. To reduce the overhead we work the other way
    around.
    We save the last piece of variable ram onto the stack and define new
    variables occupying
    this ram space. Take a look at function_03 for an example.

    function_03:
    gosub alloc4 'allocate 4 bytes for local variables
    x1 var W12 'local word variable
    y1 var B23 'local byte variable
    'code here
    goto free4 'free local variables and return from gosub

    The alloc subroutines copy the contents of the last 4 or 8 bytes of variable
    ram to the
    stack. To reduce code only 4 or 8 bytes can be freed, which is enough for
    most cases.
    See how the local variables x1 and y1 are defined to known locations inside
    the freed
    variable ram. To keep things clear, you should use these variables only
    within the subroutines
    in which they are defined (for for-next loops, counters, intermediate
    results etc.), because
    for the stamp compiler they are just aliases. Upon return from the
    subroutine you must go to
    either free4 (if you used alloc4) or free8 (if you used alloc8) to restore
    the contents of
    the variable ram. In this way we only have two statements overhead and
    direct access to the
    local variables. The same technique is applicable to program calls.
    The main advantages of these local variables is that you can avoid running
    out of
    variable space (using variables for multiple purposes which may lead to hard
    to debug errors)
    and making functions re-entrant.

    This concludes this article about stack use for the stamp.
    I hope it demonstrates the program power that a multilevel stack can
    provide.

    Peter Verkaik, May 14, 2001
    Any more suggestions are welcome.
    Please send errors, enhancements and suggestions to
    peterverkaik@e...

    SUPPLEMENT:

    I ran into the problem of retaining variable values during program
    switching.
    Thought you might be interested in my solution.
    As the stack mechanism does provide a means to retain variable values for
    the calling
    program (i.e parent), it does not for the called program (i.e. child), as
    the ram locations
    are restored upon return.
    To overcome this I found an elegant way.
    I reserve some scratchpad locations above the stack to hold program
    variables that
    have to be retained during a program call.
    Upon entry of a program these values are restored, while when doing a
    program call
    these values are saved. This reduces overhead to just 2 gosubs and 2 small
    routines.

    Retain1 var word 'retainable vars (known to program only)
    start at ramlocation 0
    '
    Global1 var word 'globals (known to all programs)
    '
    Local1 var word 'locals stop at ramlocation 25 (known to
    program only)

    'program 0

    gosub Restore0Global 'first line of code: restore
    context upon entry
    branch TargetID,[noparse][[/noparse]...]
    '
    gosub PushLocal
    put StackPointer,EN1P0
    StackPointer=StackPointer-1
    TargetID=EN6P4
    goto CallProgram
    entry01:
    'return point
    gosub PopLocal
    '
    CallProgram: 'single entry used for program calling
    gosub Save0Globsl 'save context before calling
    run TargetID
    '
    '
    Save0Global:
    for X=0 to RETAIN0SIZE-1
    put RETAIN0START-X,B0(X) 'implied array
    next 'put B0 first, B3 last (for RETAIN0SIZE=4)
    return

    Restore0Global:
    for X=0 to RETAIN0SIZE-1
    get RETAIN0START-X,B0(X) 'implied array
    next 'get B0 first, B3 last (for RETAIN0SIZE=4)
    return

    'Program 1
    Save1Global:
    for X=0 to RETAIN1SIZE-1
    put RETAIN1START-X,B0(X) 'implied array
    next 'put B0 first, B3 last (for RETAIN1SIZE=4)
    return

    Restore1Global:
    for X=0 to RETAIN1SIZE-1
    get RETAIN1START-X,B0(X) 'implied array
    next 'get B0 first, B3 last (for RETAIN1SIZE=4)
    return

    The constants RETAIN?START and RETAIN?SIZE are defined at the program start.
    TopOfScratchPad con 126 '126 or 62
    retain01 var word 'start at ramlocation 0 (program 0)
    retain02 var byte
    RETAIN0SIZE con 3
    RETAIN0START con TopOfScratchPad '126 or 62
    retain11 var byte 'start at ramlocation 0 (program 1)
    retain12 var byte
    RETAIN1SIZE con 2
    RETAIN1START con RETAIN0START-RETAIN0SIZE
    etc. until
    RETAIN7SIZE con 0 'program 7 without retainable variables
    RETAIN7START con RETAIN6START-RETAIN6SIZE
    TOS con RETAIN7START-RETAIN7SIZE 'Top Of Stack
    For programs with a RETAINSIZE=0 the gosub in the first line must be
    removed,
    so must the gosub in CallProgram and both routines Save?Global and
    Restore?Global.

    Any comments on this procedure for a (stripped down) context switch is
    welcomed.

    Regards peter.
  • ArchiverArchiver Posts: 46,084
    edited 2001-12-26 20:21
    Hi,

    Have a look at http://www.emesystems.com/BS2SX.htm
    There is a lot of information about local and global variables, and
    cross-bank calls.
    This should solve your problem, without the need of copying subroutines in
    every bank.
    I use this system, it's working great !

    Regards,

    Phil.

    Original Message
    From: "sethjaredjeromiejohnson" <sjohns10@h...>
    To: <basicstamps@yahoogroups.com>
    Sent: Wednesday, December 26, 2001 3:00 AM
    Subject: [noparse][[/noparse]basicstamps] Re: Beginner with BS2SX


    >
    > --- In basicstamps@y..., "peter verkaik" <peterverkaik@b...> wrote:
    > > Hi,
    > >
    > > The easiest way is to copy the subroutine in the first slot
    > > to the second slot. Place a remark by both the subroutines
    > > that there is a copy of this routine in an other slot.
    > > This will remind you later to change both subroutines
    > > iIf they need to be modified.
    > > There are pitfalls though, for example, variables used in the
    > > subroutine must also be available in the slot you
    > > copy the routine to.
    > >
    > > Regards peter
    >
    > Almost every section of my program is dependant on another section in
    > the program. For instance, I have the program going back to the
    > beginning often to check the state of the power button. There are
    > several instances similar to that one, and if I copied them all to
    > where they were needed (in the same slot), then I'm back to start
    > because the program is too large to fit in one slot. Is there some
    > way to get the program to recognize that the other parts of the
    > program are in different slots? Thank you very much for your help.
    >
    >
    > To UNSUBSCRIBE, just send mail to:
    > basicstamps-unsubscribe@yahoogroups.com
    > from the same email address that you subscribed. Text in the Subject and
    Body of the message will be ignored.
    >
    >
    > Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
    >
    >
    >
Sign In or Register to comment.