Shop OBEX P1 Docs P2 Docs Learn Events
Cogs, Spin and Variable sharing — Parallax Forums

Cogs, Spin and Variable sharing

Timothy D. SwieterTimothy D. Swieter Posts: 1,613
edited 2007-10-03 18:03 in Propeller 1
Boy am I glad forums exist because it is the best place to turn to have spending hours of trying to figure it out myself!

My problem:· I have a Spin routine executing in cog 0.· The cog 0 routine has a variable that it is incrementing.· I have another spin routine executing in cog 1 and it needs to see the variable in cog 0.·

Now, if the spin routine executing in cog 1 is started from within the same file as cog 0, then everything seems to work fine. (i.e. one·".spin" file contains the PUB for·cog 0 and cog 1"· When I move the PUB routine for cog 1 into its own file and add the proper OBJ code to include it then the code no longer works.· What am I missing?· I searched through the forums but have not seen anything addressing this specifically (could be that I am getting too tired though).

This code works.· Note all the code in the same file.

VAR
  byte  myTestVar
  long  stack0[noparse][[/noparse]10]
  
PUB main
  myTestVar := 0
  COGNEW(spincog1(@myTestVar), @stack0)
  
  repeat
    myTestVar ++
    PauseMSec(250)
 
PUB spincog1(_pointer) | local1
  DIRA[noparse][[/noparse]16..23] := %11111111        'Make I/O's 16 to 23 OUTPUTs
  repeat
   local1 := byte[noparse][[/noparse]_pointer]
   OUTA[noparse][[/noparse]16..23] := local1
 
PRI PauseMSec(Duration)
{{Pause execution in milliseconds.
  PARAMETERS: Duration = number of milliseconds to delay.
}}
  waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)


While this code does not work.· In other words the LEDs are not updating with the incrementing of the variable in the other cog.··Note that the following code is broken into two different files.
VAR
  byte  myTestVar
  long  stack0[noparse][[/noparse]10]
OBJ
  Blinker      : "test2.spin"
  
PUB main
  myTestVar := 0
  COGNEW(blinker.spincog1(@myTestVar), @stack0)

 
  repeat
    myTestVar ++
    PauseMSec(250)
 
PRI PauseMSec(Duration)
{{Pause execution in milliseconds.
  PARAMETERS: Duration = number of milliseconds to delay.
}}
  waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
 
 
_________________________________________________________________________________________________
The following code is in a file called "test2.spin"
_________________________________________________________________________________________________
 
PUB spincog1(_pointer) | local1
  DIRA[noparse][[/noparse]16..23] := %11111111        'Make I/O's 16 to 23 OUTPUTs
  repeat
   local1 := byte[noparse][[/noparse]_pointer]
   OUTA[noparse][[/noparse]16..23] := local1


·Thank you for the help!

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Timothy D. Swieter
tdswieter.com
One little spark of imagination is all it takes for an idea to explode

Comments

  • hippyhippy Posts: 1,981
    edited 2007-10-02 14:20
    Have you tried with a larger stack ?

    'myTestVar' gets placed after the stack so a stack overflow would corrupt what was held there. Other than that I can see nothing wrong your code.
  • Mike GreenMike Green Posts: 23,101
    edited 2007-10-02 15:02
    Tim,
    You can't start a Spin routine in another object using COGNEW/COGINIT. In other words, using blinker.spincog1 is not allowed.

    You can put a dummy startup routine in the main object that only calls blinker.spincog1 or you can put a start routine in blinker that does the COGNEW/COGINIT.

    This is mentioned somewhere in Propeller Tips and Traps as I recall.
  • deSilvadeSilva Posts: 2,967
    edited 2007-10-02 17:07
    Yes we had that some times already... and it was one of the things that left deSilva wondering.
    This issue is not explained anywhere in Paralax's documentation.

    The least thing to happen should be the compiler issue an error!

    The workaround is as this:
    VAR
      byte  myTestVar
    
    OBJ
      Blinker      : "test2.spin"
     
    PUB main
      myTestVar := 0
      blinker.spincog1(@myTestVar)
     
    _________________________________________________________________________________________________
    The following code is in a file called "test2.spin"
    _________________________________________________________________________________________________
     
    VAR
      long  stack0[noparse][[/noparse]10]
    
    PUB spincog1(_pointer)
      COGNEW(_spincog1(_pointer), @stack0)
    
    PRI _spincog1(_pointer) 
      DIRA[noparse][[/noparse]16..23] := %11111111        'Make I/O's 16 to 23 OUTPUTs
      repeat
       OUTA[noparse][[/noparse]16..23] := byte[noparse][[/noparse]_pointer]
    



    To have moved the definition of stack0 to "test2" should even be considered a good thing smile.gif
    Edit: Oops: Just didn't do that... but now!

    Post Edited (deSilva) : 10/3/2007 10:08:56 AM GMT
  • hippyhippy Posts: 1,981
    edited 2007-10-02 18:15
    deSilva said...
    The least thing to happen should be the compiler issue an error!

    100% agree.
  • Paul BakerPaul Baker Posts: 6,351
    edited 2007-10-02 18:33
    There is a use for it where the function's return value is used as the start address, therefore it is not inherently an error. As deSilva likes to say, it's been discussed repeatedly already.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • hippyhippy Posts: 1,981
    edited 2007-10-02 20:34
    I'll have to go and look for the previous discussion but isn't there a semantic inconsistency between COGNEW(method,@stack) where method is what to run within the current object, and COGNEW(method,@stack) where the method is in a sub-object and only does anything if that method returns an address ( presumably of a PASM routine ) ?

    Logically I would expect the two to be differentiated as COGNEW(@method,@stack) and COGNEW(method,@stack).

    Added : Anyone got a pointer to where this is discussed before because I cannot find it through search.parallax.com ?

    Post Edited (hippy) : 10/2/2007 8:40:41 PM GMT
  • Paul BakerPaul Baker Posts: 6,351
    edited 2007-10-02 20:38
    Hippy you are correct it's an address to an assembly routine, there is no means to start a Spin routine via the method. Is it semantically inconsistant, I suppose, I'm just sharing what the actual behavior of using COGNEW in that manner is.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • deSilvadeSilva Posts: 2,967
    edited 2007-10-02 22:18
    hippy said...
    Logically I would expect the two to be differentiated as COGNEW(@method,@stack) and COGNEW(method,@stack).
    deSilva ddressed this in his Tutorial and became lot's of remarks as to he be splitting hairs smile.gif
    N.B. :For the first "@stack" read "thePar"...
    hippy said...

    Added : Anyone got a pointer to where this is discussed before because I cannot find it through search.parallax.com ?
    Here is one http://forums.parallax.com/showthread.php?p=662426
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2007-10-03 00:30
    Thank you guys for clearing the above issue up. I now got my simple routines working across cogs and feel a bit sheepish for not seeing this eles whese in my forum search.

    So my next question is how do you recommend to deal with arrays when passing variables by pointers in spin? I have an array of byte LED and cog0 writes to this array while cog1 (or other) reads the array and performs the function. In the loop of cog1 there could be code the loads the array like the following:

    repeat 'main loop of cog
    led0 := byte[noparse][[/noparse]_pointer]
    led1 := byte[noparse][[/noparse]_pointer+1]

    This particular code looks cluncky so I feel like I am missing something in simplifying the code. Is there a way to initialize a variable in cog1 to be always pointing to the variable in cog0 without have to repeatedly do "led0 := byte[noparse][[/noparse]_pointer]".

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter
    tdswieter.com

    One little spark of imagination is all it takes for an idea to explode

  • Mike GreenMike Green Posts: 23,101
    edited 2007-10-03 01:00
    There's no way to define a variable as an "alias" for something like "byte[noparse][[/noparse] _pointer ]". You can separate the subscript as in "byte[noparse][[/noparse] _pointer ][noparse][[/noparse] i ]" for the i-th element of the byte array, but that's all the "syntactic sugar" you get.
  • Ken PetersonKen Peterson Posts: 806
    edited 2007-10-03 01:07
    Don't know if this helps, but you can also index from a pointer:

    led0 := byte[noparse][[/noparse] _pointer ][noparse][[/noparse] 0 ]
    led1 := byte[noparse][[/noparse] _pointer ][noparse][[/noparse] 1 ]

    You can't have a pointer in one cog point to a variable in another cog. You can, however, pass a pointer to HUB memory to a cog and have another cog access it as well. This is where your array should be if you want to share it between cogs.

    Dang...Mikey beat me to it again!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔


    The more I know, the more I know I don't know.· Is this what they call Wisdom?
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2007-10-03 01:29
    Hey thanks for the quick response Ken and Mike.

    YIKES! My post above looks terrible. I must have hit a font increase in the middle of my typing.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter
    tdswieter.com
    One little spark of imagination is all it takes for an idea to explode
  • Ken PetersonKen Peterson Posts: 806
    edited 2007-10-03 01:35
    easier to catch bugs that way.. smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔


    The more I know, the more I know I don't know.· Is this what they call Wisdom?
  • deSilvadeSilva Posts: 2,967
    edited 2007-10-03 09:06
    Timothy D. Swieter said...
    led1 := byte[noparse][[/noparse]_pointer+1]
    This particular code looks cluncky
    There is no help :-(
    But there is also no "overhead": It will perform as fast as it would with whatever "syntactic sugar" around.
    It has sometimes been observed that
    byte[noparse][[/noparse] _pointer+1 ]
    is noticeably faster than
    byte[noparse][[/noparse] _pointer][noparse][[/noparse] 1 ]
    This is plausible, but I have not measured it. Following that theory
    byte[noparse][[/noparse] ++copy_of_pointer ]
    should even be faster!

    Post Edited (deSilva) : 10/3/2007 9:12:01 AM GMT
  • hippyhippy Posts: 1,981
    edited 2007-10-03 18:03
    This is what the bytecode looks like for those particular versions of 'the same thing' ...

    
    ====                                  ;   result := byte[noparse][[/noparse] _pointer + 1 ]
    
    0018         A8 00           S3       PUSH     W4.WORD
    001A         36                       PUSH     1
    001B         EC                       ADD
    001C         80                       PUSH     MEM[noparse][[/noparse]].BYTE
    001D         61                       POP      VL1.LONG
    
    ====                                  ;   result := byte[noparse][[/noparse] _pointer][noparse][[/noparse] 1 ]
    
    001E         A8 00                    PUSH     W4.WORD
    0020         36                       PUSH     1
    0021         90                       PUSH     MEM[noparse][[/noparse]][noparse][[/noparse]].BYTE
    0022         61                       POP      VL1.LONG
    
    ====                                  ;   result := byte[noparse][[/noparse] ++copy_of_pointer ]
    
    0023         AA 02 A4                 USING    W5.WORD PUSH PREINC
    0026         80                       PUSH     MEM[noparse][[/noparse]].BYTE
    0027         61                       POP      VL1.LONG
    
    


    My gut feeling from that is 'byte[noparse][[/noparse] _pointer+1 ]' would have been slower than 'byte[noparse][[/noparse] _pointer][noparse][[/noparse] 1 ]' but that's contrary to reported observations. This is an area where it would be productive to run some tests.
Sign In or Register to comment.