Shop OBEX P1 Docs P2 Docs Learn Events
SPIN compiler bug??? — Parallax Forums

SPIN compiler bug???

pedwardpedward Posts: 1,642
edited 2011-12-30 13:40 in Propeller 1
Reference http://forums.parallax.com/showthread.php?136865-Writing-a-driver-for-two-steppers-is-harder-than-I-thought!&p=1062271&viewfull=1#post1062271

The short of it is that when SPIN launches a COG with COGNEW using an OBJ as the target, it calls the Start method first, then launches the COG with COGINIT and then calls the Start method again. If the Start method does not return, the program flow is halted in the COG that called COGNEW.

The workaround is to create local functions in the namespace of the calling COG that call the OBJ Start method. In this case the SPIN compiler only calls COGINIT with the Start method, which is the expected behavior.

EDIT:

Well, JonnyMac pointed out that the v1.2 of the Propeller manual states that you shouldn't call outside of the current file! Doh!

Comments

  • pedwardpedward Posts: 1,642
    edited 2011-12-29 14:45
    Sample compiler output of local method call:
    [FONT=courier new]26                        pst.start(115200)             'debug output
    Addr : 002C:             01  : Drop Anchor   
    Addr : 002D:    3A 01 C2 00  : Constant 3 Bytes - 01 C2 00 - $0001C200 115200
    Addr : 0031:       06 04 01  : Call Obj.Sub 4 1
    Addr : 0034:          37 00  : Constant Mask Y=0 00000002 2
    27                        cognew(Left,@stack)
    Addr : 0036:             43  : Variable Operation Global Offset - 0 Address
    Addr : 0037:             15  : Run           
    Addr : 0038:             2C  : CogInit(Id, Addr, Ptr)
    Addr : 0039:          37 21  : Constant Mask Y=33 Decrement 00000003 3
    28                        cognew(Right,@stack[50])
    Addr : 003B:          38 32  : Constant 1 Bytes - 32 - $00000032 50
    Addr : 003D:          DB 00  : Memory Op Long VBASE + POP Index ADDRESS Address = 0000
    Addr : 003F:             15  : Run           
    Addr : 0040:             2C  : CogInit(Id, Addr, Ptr)
    Addr : 0041: Label0002
    Addr : 0041: Label0003
    Addr : 0041: JMP Label0002
    Addr : 0041:          04 7E  : Jmp 0041 -2   
    Addr : 0043: Label0004
    Addr : 0043:             32  : Return [/FONT]
    

    Sample compiler output when calling Start method in OBJ, doesn't work:
    [FONT=courier new]26                        pst.start(115200)             'debug output
    Addr : 002C:             01  : Drop Anchor   
    Addr : 002D:    3A 01 C2 00  : Constant 3 Bytes - 01 C2 00 - $0001C200 115200
    Addr : 0031:       06 04 01  : Call Obj.Sub 4 1
    29                        cognew(R.Start,@stack)
    Addr : 0034:             34  : Constant 0 $FFFFFFFF
    Addr : 0035:             00  : Drop Anchor Push 
    Addr : 0036:       06 06 01  : Call Obj.Sub 6 1
    Addr : 0039:             43  : Variable Operation Global Offset - 0 Address
    Addr : 003A:             2C  : CogInit(Id, Addr, Ptr)
    30                        cognew(L.Start,@stack[50])
    Addr : 003B:             34  : Constant 0 $FFFFFFFF
    Addr : 003C:             00  : Drop Anchor Push 
    Addr : 003D:       06 05 01  : Call Obj.Sub 5 1
    Addr : 0040:          38 32  : Constant 1 Bytes - 32 - $00000032 50
    Addr : 0042:          DB 00  : Memory Op Long VBASE + POP Index ADDRESS Address = 0000
    Addr : 0044:             2C  : CogInit(Id, Addr, Ptr)
    Addr : 0045: Label0002
    Addr : 0045: Label0003
    Addr : 0045: JMP Label0002
    Addr : 0045:          04 7E  : Jmp 0045 -2   
    Addr : 0047: Label0004
    Addr : 0047:             32  : Return  [/FONT]      
    
    

    Yes, these are generated by BST, but [allegedly] it generates the same binaries as the PDT.
  • pedwardpedward Posts: 1,642
    edited 2011-12-29 15:02
    To add more kindle to the fire, reference this post: http://forums.parallax.com/showthread.php?136865-Writing-a-driver-for-two-steppers-is-harder-than-I-thought!&p=1062280&viewfull=1#post1062280

    Most OBJects you call obj.Start, and that function calls cognew, which works predictably because the function passed to cognew is in the local calling space. When you pass a function outside of the local calling space, the compiler generates code that CALLs the passed function, then passes the function to COGNEW. This is clearly aberrant behavior.
  • JonnyMacJonnyMac Posts: 9,198
    edited 2011-12-29 15:25
    The workaround is to create local functions in the namespace of the calling COG that call the OBJ Start method. In this case the SPIN compiler only calls COGINIT with the Start method, which is the expected behavior.

    There's no need for a "workaround" -- one can simply construct objects and their calls using standardized (and successful) mechanisms demonstrated by Parallax and hundreds of Propeller programmers.
  • kuronekokuroneko Posts: 3,623
    edited 2011-12-29 15:38
    You get what you asked for (another way of launching PASM). IIRC, putting round brackets around the method name is another way to pull you hair out. The manual actually warns you about this but somehow suggests it's not what you want.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-12-29 15:54
    obj.method, just like (obj.method), is a function call. It's not the name of a function. The compiler is very picky about what it accepts as a function name in cognew. Could the syntax have been designed better? Probably. But what we have works fine. If you want to start a foreign method in a new cog, do a cognew on a local method that calls the foreign method. This is very un-Spinlike programming, though. A foreign method that's designed to run in it's own cog should have a startup method in the same object.

    -Phil
  • pedwardpedward Posts: 1,642
    edited 2011-12-29 16:30
    Well, the short story seems to be that you MUST call COGNEW with a local method, otherwise it behaves in an unintended way. Using the EXACT same syntax yields 2 different compiled outputs, so this is a bug and furthermore it isn't documented.

    To fix the problem, COGNEW must be annotated with a note saying effectively "only pass function names that are local to the calling code".

    Furthermore, COGNEW should only be used inside the calling context of the OBJ. This means if you want to launch a routine into a new COG, you must make at least 2 routines in an OBJ, a Start routing and a function that you want to launch into it's own COG. This also allows each OBJ to reserve the exact amount of stack space it needs for each instance.

    EG:
    VAR
      long stack[50]
      long cogid
    
    PUB Start
      if cogid
       Stop
    
      cogid := cognew(Main, @stack)
    
    PUB Stop
      cogstop(cogid)
    
    PUB Main
    
      repeat
        'do something here
    
    
  • JonnyMacJonnyMac Posts: 9,198
    edited 2011-12-29 20:55
    To fix the problem, COGNEW must be annotated with a note saying effectively "only pass function names that are local to the calling code".

    For those that missed this same discussion in another thread, that clarification does in fact exist in version 1.2 of the Propeller documentation.
    1024 x 640 - 121K
  • pedwardpedward Posts: 1,642
    edited 2011-12-30 13:40
    I have to confess, it exists in the v1.1 book I have sitting here. I took up the effort in the other thread because his code really didn't look wrong at first blush. It's called learning the hard way!
Sign In or Register to comment.