Need a little bit more info about PAR
LoopyByteloose
Posts: 12,537
Whenever I read the Propeller Manual, it seems that the explanation of PAR is mainly from the point of view of starting up the Propeller. But PAR appears to shift over to a second and very useful role after a Cog is up and running.
In that second role, is its contents operating simply as a 'pointer' to a hub ram address where desired contents are to be accessed?
Or is there a better way to explain PAR in all its uses?
In that second role, is its contents operating simply as a 'pointer' to a hub ram address where desired contents are to be accessed?
Or is there a better way to explain PAR in all its uses?
Comments
-Phil
>second and very useful role
I don't see two roles, when you start a cog with cognew the first var you pass along is the HUB ram location of the pasm (raw data) code.
The second (and optional) is a 16bit number on a long boundary, eg the lower 2 bits are always zero.
99.9% of the time this number is an hub address of the (first) variable by using @ in front of it,
but there is nothing stopping you to use any number you think your cog needs to know.
This number will be stored in cog ram location $1F0 that the Assembler definition has as: PAR
Your cog code can only Read PAR on the source side, if it's on the dest side you will access the Shadow_register $1F0
You can not add to PAR, you can not accidently destroy it
If you want to Rdlong from the next long variable after the one you passed along with cognew, you need to copy PAR to Temp1 and then add +4 to Temp1
mov temp1,PAR
add temp1,#4
rdlong mydata,temp1
You can NOT: wrlong PAR,mydata
as the rule is about source side and not that you are "reading" it
Can you edit your fragment to include modifying the value read from hub and write it back to same or different location? Just to make sure I have it correct.......
Thx
-Phil
rdlong mydata,PAR ; read a long from hub address that is stored in PAR
add mydatat,#10 ; add 10 for example
wrlong mydata,PAR ; write it back to the same hub address, if you want to used PAR+4 or PAR+8 you need to store it in temp1 etc
If your locations are all over the hub ram, when you have to set up a mailbox system where you for example 10 longs in a row that have the 10 "random" hub locations (use @var...)
Thanks Tony!!
Thanks to everyone for comments so far..
Okay, Phil says you can load PAR with anything, then jazzed jumps in an says it is a READ-ONLY register.
And when I read the Propeller Manual, discussion jumps into the terms 'pseudo-register' and 'shadow register'. If I search the whole Propeller Manual v1.2, there is no real introductory discussion to 'pseudo-register' and 'shadow register' as architectural features. DiSilva's pdf on PASM also makes no mention of them.
Also, it seems that I see discussion that some of the pseudo-registers (related to the two counters) will only take new values passed through PAR.
I think I grasp that this all implies how those register addresses are hardwired to Source and Destination call in PASM. But I am a bit lost as to how to pull all this together.
When it comes to Counters (CNT and PSHA+PHSB) it's easy to picture in your mind that the Source side have the numbers ticking away all by themselves as they are hardwired to be counters.
INA is also a register hardwired to the outside as source-register, so it must be the way the cog mux its addresses that if you put these read-only on a dest side the access goes to plain ram (shadow-registers)
With PAR I see no real reason why it could not be a write/modify register, but it would be very easy to get it corrupted and with a no longer fixed value to a hub address you can never recover.
PSHx is read-and-write, but it's only the source side that is ticking away as a counter, so a write will put the value to both s & d sides but the dest side will never increase and just stay the same
The PAR is designated when the cog starts and the internal use by the cog is as a READ ONLY register. So it provides the base address where one or more Longs in hubram provide the means to transfer variables or data from other cogs.
The pseudo-register and shadow register jargon is a secondary topic that attempts to clarify important differences in the behavior of Destination and Source being used to call the PAR register and other Cog registers.
_____
Did I get this right? In other words, it pins down where begins a series of hubram addresses that can be used to store data that is too large an array for the the Cog ram or for data that is to be shared with other cogs or both.
-Phil
PAR has no architecturally defined usage - it is simply a 14 bit value passed from the program executing the coginit instruction to the program that is activated in the designated cog. The value loaded need not be an address; may be any 14 bit value used for any purpose desired.
The PAR register of a cog is written by a coginit instruction that designates that cog. Bits 31..16 and 1..0 are set to zero; bits 15..2 are loaded from 31..18 of the Destination associated with the coginit.
There is no other way to write to PAR.
Writing to a cog's own PAR can be accomplished through the use of the coginit instruction by executing coginit with a reference the cog. However, because coginit overwrites the entire contents of the cog local memory, it's hard to imagine something useful being accomplished.
I am with you on this.
From the Cog side, it is READ ONLY. From the Compiler, it can be written with any 14 bit value.
But the Propeller Tool actually assigns that value and the code one has to write only refers to PAR and PAR + offset values (in increment of 4 bytes).
++++++++++++++
The guys in the know are able to visualize and grasp what it does and how to do it (well-seasoned assembly language programers).
But to a beginner, one is looking for that 14 bit value in the PASM code. It isn't done that way.
You can also do this from PASM whose coginit instruction loads the new cog's PAR register from the most-significant 14 bits of data contained in the insturction's destination register.
Also, PAR can point to words and bytes in the hub, so long as they're long-aligned. When incrementing through a byte array, for example, the address copied from PAR gets incremented by one, instead of by four.
-Phil
One use I could see is to have a CNT value a few mS ahead in the future so two cogs started with same code that need to be synced.
But as CNT is 32bit and you only have 14bit for PAR, I guess you need to round up to nearest 10ms etc and right/left Shift the value.
Anyone done this?, though what program only need a cnt value and it never access the HUB?
And you probably need 1bit for Flag so the cog knows who it is, so now only 13bit for a CNT value
PAR cannot point to words, bytes or longs. It's not an address. It's just a 14 bit register. Once read, the contents may be used for anything.
Tony,
Why not just store a 32-bit value in memory that's suitably "far enough" in the future (say, Sync_Time := CNT + 20_000). Then the "main" thread can COGINIT the new cog and immediately WAITCNT (Sync_Time). The new cog should have as its first executable statement the same WAITCNT. The subsequent execution of each cog should be synchronized.
Since there's no explanation of how long it takes for the new COG to get to its first SPIN statement, there's no way to know what "far enough" really means. But we know that 512 longs need to be copied and that a RDLONG loop takes 16 clocks per iteration so the memory copy alone is 8192 clocks. I'd estimate twice that and guess that 20_000 is probably sufficient - but do be careful.
You'd be much better off with either locks with LOCKSET/LOCKCLR - or by using an unused IO pin that's an output in one cog and an input in the other and use WAITPNE/WAITPEQ.
-Phil
It has taken me quite awhile to fully understand that fact. But once one knows it, the PAR's purpose of pinning down a starting point for Hub address is key to transferring data between hub and cog. 14 bits just counts 8K longs.
++++++++++++++
The other item that has been very helpful to me is to learn that the READ-ONLY special registers are merely READ-ONLY when the Cog is using them, though where and how they get written to is quite varied. Obviously, the CNT register is fed by a 32 counter that just rolls over and is never touched by the programmer. The other one's need to be take on a case-by-case basis.
Thanks to all for the clarification of PAR. Though there may be odd-ball ways to use it, I am mostly interested in the role it was intended to fulfill within the Propeller.
-Phil
more instances of the same cog code - it is the PARameter block pointer so each instance
can be given different parameters.
Otherwise you don't need to use it as you can simply update the cog's variables directly
before you start it - remember a cog is simply copied from hub RAM at coginit/cognew time
and takes the values from that hub image.
In fact you can update the hub image of a cog and start another copy with different
values (so long as you wait for previous cognew/coginit's to complete), so PAR isn't
really needed at all, its just convenient.
However there is a case where it is needed, and that's for starting a Spin cog, since the
Spin interpreter is in ROM, you cannot provide parameters by overwriting its image.
(Strictly you still don't need it if the interpreter copied its parameters from a standard place
in hub RAM at start up - but that isn't thread-safe and a lock would need to be employed)
>before you start it - remember a cog is simply copied from hub RAM
Old code examples does that, but apparently it's frown on.
Self-modifying your pasm code before you cognew it is no longer acceptable.
-Phil
Only because, it's non-portable.
-P.
Yes, that's correct.