Spin Zone #10, January 2011
Bump
Posts: 592
Hello everyone, the newest Spin Zone article, From Spin to PASM and Back Again, is up!
http://www.parallax.com/TheSpinZone/tabid/781/Default.aspx
http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/prop/col/nvp10.pdf
http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/prop/code/nvp10.pdf
http://www.parallax.com/TheSpinZone/tabid/781/Default.aspx
http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/prop/col/nvp10.pdf
http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/prop/code/nvp10.pdf
Comments
I do notice that he mentions the variance in practice between using PAR to "properly" pass values to PASM routines and just "poking" the vals in. I've taken pretty much to using the poke before launch method, because it saves lots of both Hub and Cog RAM, making it the superior method, period. But he has a valid point that it makes PASM code harder to use with other languages.
However, you can get around that too! If you make the first instruction of the Cog image a jump (which you then later use as the always-needed TMP var), followed by an ordered array of parameters, you can poke the parameter values into your PASM image from any language as long as you have the indeces.
OBC
To be honest -- and I always try to be -- it wasn't my point; it was in fact made by another (perhaps RossH) vis-a-vis C and other languages that are popping up for the Propeller. Like you, Roger, I had gotten very used to poking values into my PASM code before launching, but now, since I may want to experiment with Catalina and other languages, I'm trying to write my objects so that they will work as universally as possible. It's a little extra work but a one-time thing (hopefully).
@OBC: Thanks, pal!
1. Dynamic updates. Although it may be very rare to change some of the parameters for tv.spin there may be programs where that feature is useful.
2. Avoids startup collisions. cognew takes ~8K cycles to load the cog. So bad things could happen if two SPIN objects both start the same cog at the same time, or one object invokes the start more than once in quick succession.
Not so fast...
Let's assume we are comparing localrogers's POKE technique vs passing a parameter block via PAR.
Both require a parameter block to be set up prior to launching a COG. It's just that localroger requires defining it at the start of the PASM block itself.
So...
1)Dynamic updates.
I presume that means changing parameters whilst the COG is running.
I believe this is better done through a mailbox interface, if it is ever required, rather than the initial parameter block. Mostly restarting the COG entirely with new params is as good away as any.
2) Avoids startup collisions.
Perhaps true, but start up collisions are still possible with a PAR block unless the user remembers to use a different PAR block space for each COG started. Which is more waste of memory.
Might as well remember to wait a few microseconds whilst a COG is loading its params before starting the next one.
What about a video driver? We are reaching a point now where we've got a lot of modes and signal options and resolutions available to us. If that COG is simply watching it's parameters, where ever they are, another process written in basically anything can just write a value, perhaps read one back, but maybe not, and the behavior changes. Say a driver goes from bitmap mode at low resolution, to text, or that maybe uses color redirection. Simply updating a value somewhere is nice and clean, and in the case of the color redirection, something that is very useful at runtime.
A restart requires a break in the signal, which isn't always desirable, that's all.
I like the idea of being able to just have the values in the COG image, but that kind of all breaks down when one wants to load the cog into a buffer, start it, then erase the buffer for another one.
Seems to me, being able to specify where that parameter block lives gets around that nicely. Just pass PAR, then the cog can operate relative to that for inputs and outputs. Ideally then, the COG image would never change, consuming it's unknowns from PAR, or offsets to whatever is in PAR. Applicable to multi-cog tasks as well.
RS_Jim
I wish there was a forum for students of PASM. I, for one, could more rapidly absorb the lessons of accomplished engineers once I learn C-A-T. The Propeller lab manual is indespensable but it only teaches Spin.
I wanted to ask if the #4 in the following snippet is a standard of some sort?
Larry,
He is simply advancing to the beginning of the next LONG in memory (4 bytes = 1 long)
-h
Depends on context. For example, in this snippet the PASM code is retreiving two timing values (ticks in milliseconds, ticks in microseconds) and then saving the addresses of two working variables. All of the hub (Spin) elements are longs so we have to add 4 (there are four bytes in a long) to the address (in tmp1) to get the address of the next element. The base address of the Spin variables in passed in par.
In general,
RDBYTE would be associated with add tmp, #1
RDWORD is add tmp, #2
RDLONG is add tmp, #4.
will look for prarrie dogs in small world. I doubt we will see the twinkling flowers. This is a brief trip with a very senior citizen so travel within the park will be limited.
RS_Jim
Great article, simple & concise. You ought to write a book on PASM for Spinners
Thank you for your kind comment.
If my definition of "poking" (above) is correct, then this method requires memory in hub RAM and cog RAM. Assuming n long values to be passed, a single SPIN object launching multiple PASM cogs would have n longs total in the SPIN cog and each spawned PASM cog would have n longs. With the par method, there will again be n longs in the SPIN cog and n longs per PASM cog to hold the local value. The difference I see is that each PASM cog requires extra instructions to calculate offset from the par address and rdlong into local cog RAM. Are the addidional instructions the incremental memory consumption being claimed? Putting the issue of ease of PASM code reuse with languages other than SPIN (which is beyond my understanding at this point), it seems then that the deciding factor would be: if the value can be determined before the PASM cog is launched, and does not need to be changed/queried by the SPIN code after launch, use the "poke" method. If the value cannot be calculated before the PASM cog is launched, or if the value needs to be read/modified by the SPIN code after launch, use the par method. Does this sound reasonable? Am I missing something?
As I said, this is beyond me at this point - however, if any brave soul would like to take a shot at explaining further, I'd be grateful.
Yes, I (think I) understand, and agree. That does require some kind of polling/messaging that the PASM code implements in order to "see" that the value has been changed by the SPIN cog, correct?
I'm totally stymied regarding the first clause above. How is it possible for any configuration of any code start the same cog at the same time? Wouldn't one fail? I must be missing some key knowledge here.
This comment does lead me to what might be the point (which I missed): if two instances of the same SPIN object each launch a PASM cog, and try to "poke" different values using DAT locations, there could be a conflict since while the VAR space is unique per SPIN object instance, the DAT space is shared. Is that what I'm missing? This in contrast to the par method, which uses a memory location in VAR, which is unique and not subject to collision.
Still missing something on the second point too: two successive calls to start a new PASM cog would both pick up the same "poked" values, wouldn't they? What's the mechanism for conflict here? This does beg a related question that I've search the Propeller Manual for without success: does the SPIN cognew (or coginit) call return before the cog has been launched? If so, then I suppose if the "parent" SPIN object were to want to provide different values to be "poked" into the two "child" PASM cogs, the launch/modify-poked-values/launched sequence could pose a problem. Is that what's being discussed here? (I have presumed that the coginit/cognew SPIN instruction did not return until the launch was completed).
I've searched unsuccessfull for more on the "mailbox" technique. Would someone point me towards further explanation on that? My guess at this point is that is something like a compound command (possibly passed with a "cmd" word through the par address) that might contain a "PO Box" (where it should go) and contents (the value used to update the PASM cog). Is this close?
Thanks to anyone that attempts to help explain this.