Program slots on BS2px
Shmuel
Posts: 14
Dear All,
I know about STORE, READ and WRITE and have read all those entries in the PBasic Manual. I still have some questions.
If my program·used all the space in Slot 0, can I continue the program in another Slot? I.e. does the program execute sequentially to the next slot?
I wrote a subroutine in Slot 1 and tried GOSUBing to it from Slot 0. This didn't work. Okay, so how do you use program slots?
Are they only meant for, say, data? Like this?
The point is I'm writing a program that seems will be larger than a single slot. I wasn't helped by the manual. Can anyone tell me how to use this feature of the laguage?
Thanks.
P.S. It's not because my program is so large but it's definitely bulky since this is my first program on the BS2.
I know about STORE, READ and WRITE and have read all those entries in the PBasic Manual. I still have some questions.
If my program·used all the space in Slot 0, can I continue the program in another Slot? I.e. does the program execute sequentially to the next slot?
I wrote a subroutine in Slot 1 and tried GOSUBing to it from Slot 0. This didn't work. Okay, so how do you use program slots?
Are they only meant for, say, data? Like this?
STORE 1 WRITE 0, "X" READ 0, temp DEBUG ? temp STORE 0
The point is I'm writing a program that seems will be larger than a single slot. I wasn't helped by the manual. Can anyone tell me how to use this feature of the laguage?
Thanks.
P.S. It's not because my program is so large but it's definitely bulky since this is my first program on the BS2.
Comments
If you want to transfer control somewhere other than the start of that slot, you need to do so inside the slot.
Variables and scratch-pad RAM are carried over, so one way to do this is with a SELECT in the new slot which uses a variable to determine which routine to execute.
Its a bit tricky to code, but works well.
This all comes from PBasic having been designed for a PIC and a 2K external EEPROM. The language itself can only figure 2K byte offesets. Having said that, it's quite remarkable they've found a nice method to allow you to continue to use that language with multiple program 'slots'.
·· No you cannot expand your program sequentially into another slot.· But you can transfer program control using the RUN command to run another program in another slot.· If the variables are all declared exactly the same, they will be preserved between slots.· You could also check out the following N&V article.
http://www.parallax.com/dl/docs/cols/nv/vol3/col/nv87.pdf
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support
csavage@parallax.com
http://www.parallax.com/dl/docs/cols/nv/vol3/col/nv87.pdf
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax
RUN is intended to switch execution to another slot. And STORE is·used when the·other slot is needed for·data?
How come the memory map doesn't reflect WRITEen values? Is it because the memory map only reflects tokenize-time? Not runtime?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support
csavage@parallax.com
READ and WRITE access the slot you choose with STORE (defaults to zero) while GET and PUT access the scratch-pad RAM.
Beware a couple of things about Read/Write though - writes go to EEPROM, and that has a finite life.· Probably not a major issue but one to be aware of - you can "wear it out."· On the other hand, what you stick in there is non-volatile.· Second, its entirely possible to scribble on top of your code - if you do its likely to cause the interpreter to freak out.
Get/Put writes scratchpad RAM, so there's no "Wear it out" concern, but if power is lost then so is what was in there.
In both cases you need to keep your own table of what goes where and how its referenced; that can be anything from compiler constants for simple stuff to a linked list or hash table for the more complex.
I'm doing quite a bit of very complex branching between RUN slots using SELECT - it works· well.· The App I'm working on right now is spread over 5 partitions of the 8 available for code and is consuming roughly 75% of those in total.· You just have to be careful to keep variable declarations aligned between partitions when used this way or you will get "surprises"....
I'm using a 2Pe, so I have the other half of the EEPROM for data logging (which I'm also using qutie effectively), reserving the last slot for non-volatile configuration data.
So far I've run into no issues with the architecture that I can't work around.· The only "gotcha" is the lack of a real interrupt structure that makes it difficult to have the code set an output condition and then determine elapsed time (with granularity finer than one second) accurately when it comes back through on a subsequent pass.
The speed with which I've been able to get fully-operational code running on this thing still amazes me.· I'm an old die-hard Z-80 MACRO guy, and I've done in a man-week what used to take me a man-month.· Granted, its not as "clean" nor do I have the resolution I'd have doing it the "old, hard way" but neither is there a need to write all sorts of wild support routines for various things you want to do - its pretty much all there in the language already - nor is there half the hassle doing the hardware interfacing I used to have to deal with either.· And I don't need an ICE to be able to work with reasonable speed on debugging....
Consider the following code fragment which will do what you're after:
When this code is run you will see the two "Debug" lines come up in turn.
The first time through the first partition, "bypass" is not set (we just started the program, so all variables are cleared) and so choice is set to 0 and then we run the program in partition 1.
It sees that choice is 0, prints the debug,·increments "bypass" and returns back to the first partition.
The first partition is reentered at the top.··Bypass is non-zero, so we ignore the first statement and set choice to 1, then call the program in partition 1 again (since it matches the second condition.)
This time since Choice is 1 we print the second debug line, again increment bypass, and return.
Since neither condition meets in the first partition this time through execution falls through to the "END" and stops.
(You could do this with just the one "choice" variable and a select in the top-level program, in fact, but separating it out like this makes it a bit easier to follow.)
kelvin
The problem is that if you NEED to pass data between the slots you must make sure the variables align or you're screwed, because the data DOES pass over. So if your structures don't align what you think is in one place really isn't.
The way I've taken care of this is to have the same definitions in all partitions. That sounds restrictive, but its not - I define a base variable (e.g. "W1") as a word, then define "V1" and "V2" as W1.lowbyte and W1.highbyte, and then define the actual WORKING variables from there, as in "myvalue var v1"
You can have any number of "aliases" to V1.
You can do the same thing with bits, nibs, and the like.
So long as you keep them consistent between partitions you can pass data around easily - you just have to make sure you don't scribble on something you need in the partition you're calling.
I find that it keeps me from hosing myself if I do it this way, because alignment is guaranteed.· Done like this you can go into the memory check tool (^M) and then switch between partitions - the memory map for variable storage should stay EXACTLY the same.· If it doesn't then you've got a declaration difference between the partitions you need to go find and fix.
·
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support
csavage@parallax.com
I guess that some people may think of "passed" as in a language's view like "C" or Pascal where they're allocated on the stack.
I still think in assembler though...... even after all these years [noparse]:)[/noparse]
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support
csavage@parallax.com
kelvin
slot 0:
pos2 VAR Word
pos VAR Word
step_ctr VAR Byte
dir_ctr VAR Nib
old VAR Nib
new VAR Nib
ob VAR old.BIT0
nb VAR new.BIT1
cnt VAR Word
div VAR Nib
div2 VAR Nib
div3 VAR Nib
key VAR Byte
key2 VAR Byte
slot 1:
time VAR Byte
pos VAR Word
pos2 VAR Word
speed VAR Word
ramp VAR Byte
key VAR Byte
key2 VAR Byte
slot 2:
speed VAR Word(3)
pos VAR Word
pos2 VAR Word
key VAR Word
key2 VAR Word
slot 3:
pos VAR Word
pos2 VAR Word
old VAR Nib
new VAR Nib
ob VAR old.BIT0
nb VAR new.BIT1
cnt VAR Word
pos3 VAR Word
pos1 VAR Word
div VAR Byte
div2 VAR Byte
div3 VAR Nib
step_ctr VAR Byte
key VAR Byte
key2 VAR Byte
slot 4:
key VAR Byte
key2 VAR Byte
pos VAR Word
pos2 VAR Word
pos3 VAR Word
pos4 VAR Word
pos5 VAR Word
pos6 VAR Word
pos7 VAR Word
pos8 VAR Word
spdvalue VAR Byte
slot 5:
key VAR Byte
key2 VAR Byte
pos2 VAR Word
pos8 VAR Word
pos4 VAR Word
pos5 VAR Word
pos6 VAR Word
pos7 VAR Word
spd0 VAR Word
spd1 VAR Word
spd2 VAR Word
spd3 VAR Word
spd4 VAR Word
spdmark VAR Byte
slot6:
speed2 VAR Word(3)
pos VAR Word
pos2 VAR Word
spdvalue VAR Byte
key VAR Byte
key2 VAR Byte
slot 7:
pos8 VAR Word
pos4 VAR Word
pos5 VAR Word
pos6 VAR Word
pos7 VAR Word
pos VAR Word
pos2 VAR Word
old VAR Nib
new VAR Nib
ob VAR old.BIT0
nb VAR new.BIT1
cnt VAR Word
pos3 VAR Word
pos1 VAR Nib
div VAR Nib
div2 VAR Nib
div3 VAR Nib
step_ctr VAR Byte
key VAR Byte
key2 VAR Byte
If I understand what you're doing correctly (and I'm not sure that I do), whenever you require a variable's value to be "passed" from one slot to another, you write it to EEPROM and save it initially, and then retrieve it in a subsequently run slot. From what I can gather, this is apparently done for multiple variables and multiple times, on multiple passes through the various slots. Is this correct?
If so, I've got a couple of pieces of potentially very concerning news for you. Please let me know before you run this too many times further.
Regards,
Bruce Bates
kelvin
I'm not sure why you can't or won't set this program up the way it should be, so that there are not potential pitfalls, but I'm not about to play the "doting parent" role here It's not like rerranging the variables so that they're the same in every program is anything time consuming or that it's a difficult task <sigh>.
Any way, the second, hidden problem you have is one of potential timing errors. That sounds a bit odd, so let me explain.
If you were using the parameter passing facility the way it was intended, the very instant a variable is updated in any manner, it is available globally, to any other slot. With your EEPROM abusive method, you must remember to write any changed parameter to EEPROM, as soon as it is updated, before heading off to any other slots. You also need to remember WHICH parameters will be needed elsewhere as well. This is only 1/2 the problem though.
Now, when you arrive in a different slot, you must remember to fetch any parameters which may have changed in another slot, and also remember WHICH parmeters you will need to fetch. Since, in the target slot, you have no idea what has changed and what hasn't, elsewhere, you must waste the time of re-fetching EVERY parameter which MIGHT have changed. I can only guess that wasted time, and programing inefficiencies are not important in this program.
If you head for a slot before a variable representing a passed parameter has been saved - oops, when there is no need for any oops. So too, if you attempt to use it before "refreshing" it, oops again.
For my money, all this unnecesssary "remembering" isn't worth it, since all it might give me is the ability to write code which is inherently difficult to follow. When I write a program today, I want to be able to pick it back up years from now, and between the straight forward, logical program flow, and the included documentation, I'll see exactly what I was doing with hardly any thought. I also want others who may succeed me, to be able to do the same thing. IMHO, your "scrambled parameters" method is a maintenance programmer's worst nightmare.
At this juncture, "Have it YOUR way" begins to apply. If I were handed a program with a variable parameter list to fix or maintain, I'd just hand it back and say "No thanks, I don't need any more headaches today"
Regards,
Bruce Bates