The PAR register
LoopyByteloose
Posts: 12,537
I keep wondering, does the PAR register never change once the Propeller starts a Cog (unless the Cog is stopped and restarted with a different PAR value)?
Comments
Which PAR register? It has a shadow in COG ram as I understand it, so when you access it as
a source register you get the true PAR register, when as a dest register you get the shadow. The
true register is read-only from cog code, only the hub can change it (via cognew/coginit). The
true register is 14 bits (two trailing bits are hardwired as 0), if I understand things.
Does one need to worry about these shadow registers when writing code? I don't understand this aspect of the Propeller but I feel like I can usually get the Propeller to do what I want (which is very fun).
How helpful would it be to understand this aspect of the Propeller and if it's important to know where do I learn about it? Okay, even if it's not very important where do I learn about it? Is it in the datasheet?
A. The PAR register I refer to is one of 16 in each cog.
B. Its contents seem to point to a starting point for loading the compiled assembly language into a cog.
Not sure where this 'shadow' register would exist, or why. But Mike G does say it does exist in the destination field of PASM.
The compiler might also use it plus and additional offset to locate variables, constants, routines, and so on in hubram (aka main ram) after the code actually starts to run. I am a bit uncertain if the second purpose would over-write the the code that was loaded into cog ram.
Does the 'shadow register' have any unusually clever alternative purpose, or is this just a factoid to be kicked about?
Also, writing to PAR's shadow register does not change the contents of PAR when read as a source register.
-Phil
You can also "poke" the values (or addresses) into the longs before launching the cog.
Apparently poking the values in before launching is bad form since it makes the object harder to convert for use with C.
But code like that below always bugs me since it uses up so much of the cog RAM.
But I just had a brilliant idea. Why not reuse this cog RAM for variables normally reserved with the "res" statement?
Once a line of code has been executed (and assuming it's only executed once), it could then be used for variable storage.
The main downside to doing this would be the code would be harder to read.
(Why does the second line of code get bumped up with the first in code blocks? (I've fixed it here, but it's annoying.))
I try no to use cog longs as buffers and instead read hub and insert in to self-modifying code in the first place.
But could be a wash that any longs are saved depending if you have to reset t1 with PAR more often.
Thanks Tony, I hadn't noticed that.
It's not my code. I was just looking for an example of reading in a list of variables from hub and it was the first one I saw.
I am using the object in a project which is starting to get tight on space so I'll clean up the object a bit to save some room. Thanks for pointing it out.
Thanks Tony. I knew there was a way to do that but the self-modifying code still makes my head swim.
It seems like your code would be useful even with 5 longs needing to be copied since I could reuse t1 and t2 as temp variable elsewhere.
As long as you got my head swimming, could you reduce the above code by one line? What if you add to both the source and the destination at once?
Of could you even do away with t1?
I'm going to stop before my head explodes.
Thanks Tony.
>:loop rdlong 0-0, 0-0 'pulseHighTicks first
No, though rdlong allows direct addressing :loop rdlong 0-0, #0-0
You would be limited to the first 512bytes (128longs) of hub ram
And with modular code, you should not count on your reserved hub variables to be located at a specific block.
So the source must point to a cog variable that holds the whole 32bit address.
You're right. I knew that.
Did I miss anything with my thought about adding to both the destination and source at once?
BTW, The code is from a PlayStation 2 driver. I modified the driver to read the analog button values (among other things).
I'm going to post a more recent version (I'm using the object in my robot remote project) but I think I'll add your loop idea to the object before posting an updated version.
Thanks for the code example.
>my_modify long (1<<9) + 4 'equ 516, as direct add's can only do 0-511
That part would have worked.
Some people would feel worried that rollover from the lower 9bits will corrupt the upper 9bits.
But as you loop count take in to account your allotted hub ram and cog ram windows,
S will not corrupt D, and D will not corrupt I.
On second thought I don't think it would work. I'm treating the source as immediate.
It wouldn't add 4 to t1 it would pretty much just mess it up. My guess is it would use the number stored in delayTime (whatever that might be) as the new hub address to read from.
I'll stick with your original version.
Did I mention how I feel about self-modifying code?
That is why I added # in front of 0-0
>>rdlong allows direct addressing :loop rdlong 0-0, #0-0
So it will work if you knew the hub array is located in the lower 128longs (bad programming though)
>Did I mention how I feel about self-modifying code?
Think of it as merging opcode and a reserved variable in to one.
With a label in front of a opcode you will know its location and the D and S field
can now be changed on the fly (with a least another line of code before it's reached)
Okay. Thanks again.
So still a bad idea.