Shop OBEX P1 Docs P2 Docs Learn Events
Indirect Addressing in Spin — Parallax Forums

Indirect Addressing in Spin

JamesxJamesx Posts: 132
edited 2008-07-11 17:50 in Propeller 1
Could someone direct me to a clear explanation of how indirect addressing works in Spin? The explanation in the manual associated with the "@" symbol starts, but I cannot seem to find a complete working example.

What I'm trying to do is have one method (or object) change a variable that can then be read by another method. Not passed like a result, but changing continuously in one cog, to be read by another cog.

Thanks

Comments

  • Ken PetersonKen Peterson Posts: 806
    edited 2008-06-24 19:18
    @Jamesx: If they are two different objects, then you can't·access the same variable by name because variable names are only in scope within a given object. You can have one object determine the address of a variable

    var_ptr := @variable ' var_ptr must be long but variable can be any type.

    Then pass it to the other object, which would access the variable as follows:

    LONG[noparse]/noparse]var_ptr] := long_value[color=white]·[/color] '[color=white]·[/color] WORD[noparse][[/noparse and BYTE[noparse]/noparse can also be used where appropriate
    -or-
    long_value := LONG[noparse][[/noparse]var_ptr]

    You would only need to pass the pointer once, i.e., during an initialization routine because once a variable·is defined it will always be at the same address.· Subsequently you can access the variable with the LONG[noparse]/noparse, WORD[noparse]/noparse, and BYTE[noparse]/noparse functions.

    If you have two methods within the same object, then you can access the variable from both methods by name and do not need to use the pointer.

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


    Post Edited (Ken Peterson) : 6/24/2008 7:27:47 PM GMT
  • JamesxJamesx Posts: 132
    edited 2008-06-25 00:27
    Ken:

    Thanks for the direction. This is confusing stuff, and it will take a bit to test your suggestions. In the meantime, I'm looking at a the Propeller Manual and it describes the use of @. Using this little program, the output is 0. But it seems to me it should be 5.

    Any ideas would be welcome.

    J

    OBJ
      OLED  : "uOLED-96-Prop_V4RayAsm"  
      snum  : "Simple_Numbers"
    
    VAR
      byte Str[noparse][[/noparse]10]
    
    PUB Main |i,j
      OLED.InitOLED
      GetString(@Str)
      Oled.PutText (0,2,2, 255,255,255, snum.dec(str))     
        
    PUB  GetString(Str1)
       Str1[noparse][[/noparse]0]:=5
    
    
    
  • TimmooreTimmoore Posts: 1,031
    edited 2008-06-25 00:32
    try byte[noparse][[/noparse]str1][noparse][[/noparse]0] := 5. You pass str to .dec rather than str[noparse][[/noparse]0]

    Post Edited (Timmoore) : 6/25/2008 12:44:50 AM GMT
  • JamesxJamesx Posts: 132
    edited 2008-06-25 01:14
    Thanks. This business is slowly starting to phase in out of the fog.

    The following makes sense, and works! The trick was figuring out the special commands (Byte, Word and Long) that are needed to put data into a variable's location, after it's address is passed.

    I've got the passing between methods. Next is to figure out how indirect passing works between objects...
    J


    GetString(@Str)
    Oled.PutText (0,2,2, 255,255,255, snum.dec(str))

    PUB GetString(Str1)
    Byte [noparse][[/noparse]Str1]:=5
  • hippyhippy Posts: 1,981
    edited 2008-06-25 12:03
    Looks like you've got it. Use of suitable naming ptrStr, strPtr or whatever takes you fancy instead of Str1 etc can help you remember ( and help readers understand ) you're dealing with a pointer to something.

    To be a pedant with Ken's "var_ptr must be long", as the Prop I memory is only 64K ( 32K RAM, 32K ROM ), any pointer can be held in a word but that won't be the case with the Prop II so it's a good habit to get into using longs for all pointers.
  • Nick McClickNick McClick Posts: 1,003
    edited 2008-07-10 21:16
    I had to look pedant up in the dictionary...
    Just to make sure I've got it;
    
    VAR
    LONG Testdata
    
    PUB main
     Repeat
        Display(testdata)
        waitcnt(clkfreq / 2 + cnt)
        modify_d
    
    PUB modify_d
     testdata ++
    
    



    The method modify_d will increment testdata, and when I call the method Display, the new value of testdata will be passed. So, anytime I want to modify a VAR within a single object (on the same cog), I don't need to use the Symbol address operator (@).

    Using a new cog, If I do;
    
    VAR
    LONG Stack[noparse][[/noparse]50]
    LONG Testdata
    
    PUB main
     Repeat
        Display(testdata)
        waitcnt(clkfreq / 2 + cnt)
        cognew(modify_d,@Stack[noparse][[/noparse]0])
    
    PUB modify_d
     testdata ++
    
    



    Will start a new cog to run the method modify_d. But that new cog won't know where the variable 'testdata' came from, and will likely Smile out. To do this the right way;

    
    VAR
    LONG Stack[noparse][[/noparse]50]
    LONG Testdata
    
    PUB main
     Repeat
        Display(testdata)
        waitcnt(clkfreq / 2 + cnt)
        cognew(modify_d(@testdata),@Stack[noparse][[/noparse]0])
    
    PUB modify_d(addr)
     LONG[noparse][[/noparse]addr]++
    
    



    The new cog will take a long, starting at addr, and increment. When the first cog reads testdata, it will get the newly written value. It works the same way if you're calling a new object.
  • bozobozo Posts: 70
    edited 2008-07-11 11:24
    won't the repeat loop code in main kick off a new cog each time through the loop?
  • hippyhippy Posts: 1,981
    edited 2008-07-11 16:50
    To expand on bozo's comment, you only want one CogNew ...

      cognew(modify_d(@testdata),@Stack[noparse][[/noparse]0])
      Repeat
        Display(testdata)
        waitcnt(clkfreq / 2 + cnt)
    
    
    



    In the second example the separately launched Cog will know where testdata is in memory so that will work, but only because it's in the same object ( objects aren't the same as cogs ), but the last example would be necessary if the modify_d() were in another object, and it works even when it isn't. The advantage is that you could change "modify_d(@testdata)" to "modify_d(@somethingElse)" if you needed to and the modify_d() doesn't need to change.

    You can also use @Stack rather than @Stack[noparse][[/noparse]0]; means the same and is less typing.
  • jazzedjazzed Posts: 11,803
    edited 2008-07-11 17:50
    Treatment of spin arrays or pointers with long/word/byte[noparse]/noparse[noparse]/noparse syntax confuses me all the time.

    I've just settled on thinking of the long/word/byte qualifiers as something of a type cast.
    Using that, I interpret a string in the same way as a C pointer.

    So accessing characters in a string like sp := string("Hello") can be done as byte[noparse][[/noparse]sp+index]
    (or byte[noparse][[/noparse]sp][noparse][[/noparse]index] as defined by spin). If sp (a pointer) is the address of something it works.

    The sp pointer is an address where Hello is stored as "H","e","l","l","o",0 . To get "e" it can
    be written as somevar := byte[noparse][[/noparse]sp+1]. I suppose the same statement can be written as
    somevar := byte[noparse][[/noparse]sp] which means something entirely different for most languages
    (not bad, just different).

    The problem I often have with this thinking is with word and long. Expression word[noparse][[/noparse]sp+1]
    still points to "e", but it also delivers "el" in some form rather than the more natural,
    to me at least, "lo"; to get "lo" one must use word[noparse][[/noparse]sp+2]. It seems word[noparse][[/noparse]sp] would
    deliver the same value as word[noparse][[/noparse]sp+2]. The same can be extended to long.

    Somebody yell if this is wrong [noparse]:)[/noparse]

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


Sign In or Register to comment.