Shop OBEX P1 Docs P2 Docs Learn Events
Need a little bit more info about PAR — Parallax Forums

Need a little bit more info about PAR

LoopyBytelooseLoopyByteloose Posts: 12,537
edited 2014-06-10 14:16 in Propeller 1
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?

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-06-06 10:01
    In that second role, is its contents operating simply as a 'pointer' to a hub ram address where desired contents are to be accessed?
    You can load PAR with anything to pass to a new cog, so long as its two lower bits are zero. Typically, PAR will point to a long-aligned address in the hub, but it doesn't have to. BTW, that's not PAR's "second role"; it's its only role.

    -Phil
  • jazzedjazzed Posts: 11,803
    edited 2014-06-06 10:04
    PAR is also read-only.
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-06-06 10:13
    manual: PAR: the value stored into it via COGINIT and COGNEW is limited to 14 bits: a 16-bit word with the lower two bits cleared to zero.
    >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
  • frank freedmanfrank freedman Posts: 1,983
    edited 2014-06-06 12:24
    Tony,
    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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-06-06 12:31
    tonyp12 wrote:
    You can NOT: wrlong PAR,mydata
    as the rule is about source side and not that you are "reading" it
    You wouldn't do that anyway. The correct form is: wrlong mydata,PAR. The hub address for both reads and writes is always in the source field.

    -Phil
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-06-06 13:05
    >modifying the value read from hub and write it back to same or different location

    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...)
  • frank freedmanfrank freedman Posts: 1,983
    edited 2014-06-06 17:08
    Had to ask; if I was looking to make sure I had it right, probably a whole bunch more out there lurking. If I asked the next most redundant question in the pasm world.... so be it.


    Thanks Tony!!
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-06-07 04:56
    You can load PAR with anything to pass to a new cog, so long as its two lower bits are zero. Typically, PAR will point to a long-aligned address in the hub, but it doesn't have to. BTW, that's not PAR's "second role"; it's its only role.

    -Phil

    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.
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-06-07 05:25
    > hardwired to Source and Destination
    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
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-06-07 07:10
    Well, I went back to my Propeller Manual v1.01 and I think I have got it now.

    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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-06-07 10:21
    Okay, Phil says you can load PAR with anything, then jazzed jumps in an says it is a READ-ONLY register.
    We're both right. You load it by starting a new cog and specifying its contents at that time. It cannot be reloaded from the cog you started, though.

    -Phil
  • ksltdksltd Posts: 163
    edited 2014-06-07 14:40
    Yet another example of remarkably weak documentation and lack of formality in describing the runtime model.

    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.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-06-07 23:15
    @kstld
    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.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-06-07 23:56
    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).
    Not exactly. If you start a new cog from Spin, the argument that assigns the value to PAR can be any expression. Once the expression is evaluated at runtime, bits 15..2 of the result get written to the new cog's PAR register.

    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
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-06-08 09:06
    Beside pointing to a long aligned hub address,
    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
  • ksltdksltd Posts: 163
    edited 2014-06-09 11:23
    Phil,

    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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-06-09 11:50
    ksltd wrote:
    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.
    I believe I said that it can be anything, including an address that points to bytes, words, or longs in the hub (which just happens to be its usual applicaiton).

    -Phil
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-06-09 21:32
    One of the more interesting facts about the Propeller is that the Cog RAM is 32bit registers in general (The PAR register seems to contradict that with being only 14 bits, but that is just because it is purposely holding the Long alignment of the HubRAM's 32kb); while the Hubram registers are in bytes, just 8 bits. So transfers of Longs from the HubRAM to the CogRAM take 4 contiguious byte registers. The EEPROM transfers a compiled program binary just byte for byte to get the Propeller started.

    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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-06-09 22:57
    The 14-bit limitation of the PAR register is a direct consequence of how data has to be packed in the destination register of PASM's coginit instruction. There just isn't room for more than 14 bits, along with the PASM starting address (14 bits), the cogid (3 bits), and the new/init flag (1 bit). 14 + 14 + 3 + 1 = 32.

    -Phil
  • Mark_TMark_T Posts: 1,981
    edited 2014-06-10 02:29
    One thing that seems to have been forgotten here - PAR is only needed if you start two or
    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)
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-06-10 04:36
    So in summary, PAR contains a 14-bit value that is set by coginit. It cannot be changed by the cog that accesses the PAR register. The value read from the PAR register will be positioned in bits 2 - 15 in the result register, with all the other bits set to zero. The 14-bit value can be used for any purpose in software. When used to represent a hub address, it is standard practice that the address must be long-aligned so that the two least significant bits are zero.
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-06-10 08:43
    >you can simply update the cog's variables directly
    >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 Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-06-10 09:31
    The fact that a few people frown upon the practice, does not make it "unacceptable." I still do it because it's simple and convenient. As long as your code makes clear what you're doing, I see no problem with it.

    -Phil
  • jazzedjazzed Posts: 11,803
    edited 2014-06-10 11:35
    tonyp12 wrote: »
    >you can simply update the cog's variables directly
    >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.


    Only because, it's non-portable.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-06-10 11:38
    jazzed wrote:
    Only because, like Phil, it's non-portable.
    :)

    -P.
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-06-10 13:36
    jazzed wrote: »
    Only because, it's non-portable.
    I don't quite understand that comment. PASM only works on the Propeller, so it's non-portable by its nature. The main problem with stuffing values into PASM code before starting a cog is that it doesn't work well when using the PASM code with C. One way around this is to move all of the variables to be stuffed to the beginning of the PASM code starting at cog address 1. This way they are all in a known location. Cog location 0 just contains a jump around the variables, and can be used for a read/write location after the cog starts up.
  • jazzedjazzed Posts: 11,803
    edited 2014-06-10 14:16
    Dave Hein wrote: »
    PASM only works on the Propeller, so it's non-portable by its nature. The main problem with stuffing values into PASM code before starting a cog is that it doesn't work well when using the PASM code with C.


    Yes, that's correct.
Sign In or Register to comment.