Shop OBEX P1 Docs P2 Docs Learn Events
Oh, I love pointers, but they don't love me! — Parallax Forums

Oh, I love pointers, but they don't love me!

ErNaErNa Posts: 1,752
edited 2009-08-03 07:09 in Propeller 1
Hello,
I'm still confused about the use of the @@ operator.

I start a process and pass a pointer to a field of pointers:
CON      NmbrOfParameters = 5  ' Number of parameters passed to the started process via an array of pointerss
Dat ProcParameters long  @Parameter1, @Parameter2, @Parameter3, @Parameter5, @ Parameter5



This data statement allows me to place the Parameters somewhere.

The first parameter tells the start procedure the number of entries in the array:
  Parameter1 := NmbrOfParametersAnzScre  ' Tell the startroutine the number of valid addresses




Because there is an different between compile and runtime addresses, I do a manual address correction, a method, which works but is not nice:

  repeat i from 0 to NmbrOfParameters -1                      ' Manually add fix offset
    ProcParameters[noparse][[/noparse] i] += 16
  i := Process.start(@ProcParameters) -1                         ' starting process 




The start routine works like follows:

PUB Start( PointerToArray ) | i

  Stop 
  ' Store a local pointer to the variables passed to process via pointer array

  repeat i from 0 to LONG[noparse][[/noparse]LONG[noparse][[/noparse]GlobPtr +   0]]-1              ' First element is the NmbrOfParameters
    LONG[noparse][[/noparse]@LoclPtr + (i<<2)] := LONG[noparse][[/noparse]GlobPtr + (i<<2)]    ' Adresses are stored to an local array
      
  ifnot ID_cog
    ID_cog := cognew(CogProz, @Sk) + 1
  Long[noparse][[/noparse]CommandPtr] := 0 ' Show that process is up and running bei resetting NmbrOfParameters to zero

  Result := ID_Cog 




This procedure does the job but I have the strong feeling, it is not elegant. I should be able to correct the offset with the @@-Operator, but didn't find out, how. Any hint or help is appreciated.

ErNa

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
cmapspublic3.ihmc.us:80/servlet/SBReadResourceServlet?rid=1181572927203_421963583_5511&partName=htmltext
Hello Rest Of The World
Hello Debris
Install a propeller and blow them away wink.gif

Post Edited (ErNa) : 8/1/2009 9:35:18 AM GMT

Comments

  • mparkmpark Posts: 1,305
    edited 2009-08-01 00:30
    Hi ErNa! I'm confused—what's ProzScre? GlobPtr?

    Anyway, the manual fixup you're doing, adding 16, is what @@ does, except @@ adds the correct offset for the object it's in (it's not always 16).
  • ErNaErNa Posts: 1,752
    edited 2009-08-01 09:47
    Hello Michael,

    you were right, this happens if you copy and paste. ProcParameters is the pointer to the process control block of the started process.
    I tried to move the initialisation of the pointers (add the offset) into the called routine where I already have the loop to copy them to the local storage.
    I thought that would be possible, but didn't find an elegant way.



    when I change the code to:

      repeat i from 0 to NmbrOfParameters -1                      ' Manually add fix offset
         ProcParameters[noparse][[/noparse] i] := @@ ProcParameters[noparse][[/noparse] i]
      i := Process.start(@ProcParameters) -1                         ' starting process 
    
    



    it works. This is better for 16 as an fixed offset is just quick and dirty.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    cmapspublic3.ihmc.us:80/servlet/SBReadResourceServlet?rid=1181572927203_421963583_5511&partName=htmltext
    Hello Rest Of The World
    Hello Debris
    Install a propeller and blow them away wink.gif
  • ErNaErNa Posts: 1,752
    edited 2009-08-01 13:47
    I went on a little bit:
    The offset being 16 and I'm just adding an offset, I moved this to the called start routine. Now I have:

    
    CON AddrOffse = 16
    
    PUB Start( PointerToArray ) | i
    
      Stop 
      ' Store a local pointer to the variables passed to process via pointer array
    
      repeat i from 0 to LONG[noparse][[/noparse]LONG[noparse][[/noparse]GlobPtr +   0] + AddrOffs  ]  -1              ' First element is the NmbrOfParameters
        LONG[noparse][[/noparse]@LoclPtr + (i<<2)] := LONG[noparse][[/noparse]GlobPtr + (i<<2)] + AddrOffs         ' Adresses are stored to an local array
          
      ifnot ID_cog
        ID_cog := cognew(CogProz, @Sk) + 1
      Long[noparse][[/noparse]CommandPtr] := 0 ' Show that process is up and running bei resetting NmbrOfParameters to zero
    
      Result := ID_Cog 
    
    



    Now I manually add the offset but I was not able to do this with @@, but couldn't analyze, what @@ does now, because I have no debugging tool in this environment

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    cmapspublic3.ihmc.us:80/servlet/SBReadResourceServlet?rid=1181572927203_421963583_5511&partName=htmltext
    Hello Rest Of The World
    Hello Debris
    Install a propeller and blow them away wink.gif
  • SamMishalSamMishal Posts: 468
    edited 2009-08-02 06:55
    ErNa,
    There are two occasions you would use a pointer:
    1-····· At run time
    2-····· At compile time
    During run time when you use a pointer to a variable whether it is in a Var section or a Dat section you will get the right address all the time. There is no need to use @@ to correct it.
    At compile time referencing the address of a variable is resolved in relation to the start of the object. So when an @ is resolved at compile time it refers to the RELATIVE address of the variable to the start of the object.
    At run time the object may not fit where the compiler assumed it did and thus the ACTUAL address of the variable will not be the same as the address calculated at compile time. So the @@ operator is used to resolve the actual address of the variable according to the already stored relative address.
    The @@ operator is then only of use when you have a need to use @ at compile time and you need to correct it at run time.
    This mostly occurs if you use the @ to store the address of a variable in a location within the DAT section which gets resolved at compile time and thus you will need to correct it later at run time.
    This is usually necessary if you need to store a LIST of variable or memory locations that are not easily calculated from a BASE address at run time.
    ·
    Consider these two programs
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
     
    OBJ
      Debug    : "FullDuplexSerial"
     
    PUB Main|i
      Debug.Start(31,30,0,115200)
      waitcnt(ClkFreq*2+cnt)  'wait a bit to give time to activate the Serial terminal
    
     
      Debug.Tx(16)
      repeat i from 0 to 2
         Debug.Str(@@StrList[noparse][[/noparse]i])  'the @@ is needed to adjust the compile time address stored
         Debug.Tx(13)             'in the StrList[noparse][[/noparse]0] and StrList[noparse][[/noparse]1] etc.
                                  'try to remove the @@ and see the result
      
      'Can you predict what the following lines will do???
      Debug.Tx(13)
      Debug.Str(@StrB)
     
    Dat
      'storing variable lenght Byte arrays thus there is no easy way to calculate
      'the start address of each string
      StrA byte "This is a test to see how it works",0
      StrB byte "Another test string",0
      StrC byte "Yet one more string for more testing to see how",0
     
      'thus we need an array that has the addresses of the starts of each string (or byte array) 
      StrList Long @StrA, @StrB, @StrC     'stores compile time addresses for start of each string
             
    


    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
     
    OBJ
      Debug    : "FullDuplexSerial"
     
    PUB Main|i
      Debug.Start(31,30,0,115200)
      waitcnt(ClkFreq*2+cnt)  'wait a bit to give time to activate the Serial terminal
    
     
      Debug.Tx(16)
      repeat i from 0 to 2
         Debug.Str(@StrA[noparse][[/noparse]i*48])  'notice how we can calculate the address of each string (byte array)
         Debug.Tx(13)            'from the BASE @StrA due to the fact that each is of KNOWN length (48)
     
      'can you predict the result of the following code???
      Debug.Tx(13)
      Debug.Str(@StrC-48)
     
    Dat
      'storing variable consistent length Byte arrays each is 48 bytes long
      'thus at run time we can CALCULATE the address of the start of each string (byte array)
      'from the BASE reference of the @StrA
      StrA byte "This is a test to see how it works             ",0
      StrB byte "Another test string                            ",0
      StrC byte "Yet one more string for more testing to see how",0
     
      'notice there is now no need for the list of start addresses since we can claculate
      'them at run time from the formula @StrA[noparse][[/noparse]i*48]....48 being the consistent length of each         
    

    In your program (from what I can discern)· you do not need the first example since your variables are numerical and thus you know their lengths and can just use the method of the second example above.
    I think you need to rethink the way you are doing your code.
    Nevertheless, if you do need to do it the way you are doing it then now you know how the @@ operator works and what it does.
    ·
    Samuel
  • ErNaErNa Posts: 1,752
    edited 2009-08-02 15:36
    The problem with pointers arises from the fact, that a pointer created a compile time is different from that one updated at runtime.
    So if I have a
    DAT
    VariablePtr Long @Variable1

    and access to that Variable1 Value := @@VariablePtr
    this will work (at least I hope)

    but if I change VariablePtr at runtime to @Variable2

    I gain access to Variable2 with Value := @VariablePtr

    So, if I initialize a pointer via DAT, I have to update this pointer when the program starts and after that I can use this pointer in a "normal" way.

    
    CON AddrOffse = 16
    
    PUB Start( PointerToArray ) | i
    
      Stop 
      ' Store a local pointer to the variables passed to process via pointer array
    
      repeat i from 0 to LONG[noparse][[/noparse]LONG[noparse][[/noparse]GlobPtr +   0] + AddrOffs  ]  -1              ' First element is the NmbrOfParameters
        LONG[noparse][[/noparse]@LoclPtr + (i<<2)] := LONG[noparse][[/noparse]GlobPtr + (i<<2)] + AddrOffs         ' Adresses are stored to an local array
          
      ifnot ID_cog
        ID_cog := cognew(CogProz, @Sk) + 1
      Long[noparse][[/noparse]CommandPtr] := 0 ' Show that process is up and running bei resetting NmbrOfParameters to zero
    
      Result := ID_Cog 
    
    




    This piece of code is running as expected. LONG[noparse][[/noparse]GlobPtr] gives me the content of address GlobPtr and this content is again a pointer initialized via DAT. Now I expect @@LONG[noparse][[/noparse]GlobPtr] to add the offset, that is, 16. But that doesn't work. So, where is the mistake?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    cmapspublic3.ihmc.us:80/servlet/SBReadResourceServlet?rid=1181572927203_421963583_5511&partName=htmltext
    Hello Rest Of The World
    Hello Debris
    Install a propeller and blow them away wink.gif

    Post Edited (ErNa) : 8/2/2009 3:43:57 PM GMT
  • mparkmpark Posts: 1,305
    edited 2009-08-02 16:51
    When you say it doesn't work, what do you mean exactly? What happens?

    What is LoclPtr? Why is there an AddrOffse and an AddrOffs?
  • SamMishalSamMishal Posts: 468
    edited 2009-08-02 18:56
    ErNa said...
    The problem with pointers arises from the fact, that a pointer created a compile time is different from that one updated at runtime.
    So if I have a
    DAT
    VariablePtr Long @Variable1

    and access to that Variable1 Value := @@VariablePtr
    this will work (at least I hope)
    If you are trying to get the value of the variable then that will not work
    this will work value := Long[noparse][[/noparse]@@variableptr]

    @@variableptr will give you an adjusted address, not the value.

    I think your confusion comes from C++. @@ is not a pointer to pointer nor is it a dereferencing of the pointer.
    All @@ does is do automatically what you were doing manually by adding 16. But the system does it correctly in case
    more or less than 16 is needed.....you determined 16 by looking at the difference in pointers no??? the system guarantees
    that the correct value (could be 16 or less or more) is used to adjust the address when you use @@......but it is still an address.

    In C++ we use * to indicate a pointer type, we use & to reference the address and we use * to dereference the address.

    In Spin @ is to reference the address and Long[noparse]/noparse or Byte[noparse]/noparse or Word[noparse]/noparse is used to dereference the address. Also in Spin
    you do not need to specifically declare a pointer variable as such, it is just another LONG variable.

    So do not confuse @@ with **. It has no relation to C++ except in @ being a pointer referencing operator. @@ is a
    pointer adjuster operator that adds (or subtracts) a certain·offset to the already stored address value.
    ErNa said...
    but if I change VariablePtr at runtime to @Variable2

    I gain access to Variable2 with Value := @VariablePtr

    So, if I initialize a pointer via DAT, I have to update this pointer when the program starts and after that I can use this pointer in a "normal" way.

    If you change the VariablePtr at run time to @Variable2 you still can access the value using Long[noparse][[/noparse]@@variableptr].
    but why......you can just say value:= Variable2.................

    This is what I am talking about when I said that you need to rethink your code......I think you are overcomplicating the
    program more than you need to................

    If all you want is to have an array (list) of variables (longs, words or bytes)·and you are interested in accessing them
    in a loop then you do it in either of two ways:
    1- using an array
    ··· Var
    ······· Long myvalues[noparse][[/noparse]20]
    ···
    ··· Pub Main|i,x
    ······· repeat i from 0 to 19
    ············ x:= myvalues[noparse][[/noparse]i]

    2- by using the address of a starting variable in the list
    ··· Var
    ······ Long v1, v2, v3··· 'you can use bytes or words

    ··· Pub Main|i,x
    ······· repeat i from 0 to 2
    ··········· x := Long[noparse][[/noparse]@v1][noparse][[/noparse]i]·· 'use word or byte if your variables are words or bytes
    ··········· 'or you can do it this way knowing that longs are 4 bytes
    ··········· x := Long[noparse][[/noparse]@v1+i*4]·· 'if your variables are bytes use 1 not 4 and if words then use 2 not 4
    ··········· 'or you can use << 2 to multiply by 4· <<1 to multiply by 2 (for words) and no shifting for bytes
    ··········· x := Long[noparse][[/noparse]@v1+i<<2]


    As you can see there is no need to reference the variables in a·DAT section since their addresses can be
    determined at run time with a simple formula.

    The only time you need to reference the addresses in a DAT section is if there is·a need to access the variables
    in a sequence and they are not contiguous and are of varying length such as there is no easy way to calculate
    the addresses of each using a formula.

    I think you are overcomplicating your program.

    Samuel

    ···

    Post Edited (SamMishal) : 8/2/2009 11:45:15 PM GMT
  • ErNaErNa Posts: 1,752
    edited 2009-08-02 19:44
    What is my intention:

    I run different processes in different cogs and these processes communicate.
    The communication take place via LONG[noparse][[/noparse]Address].

    It was often discussed, how variables are passed to processes, but I'm looking for a more general approach and it works, so far.

    I start a new cog and pass a pointer to an array of pointers, initialized in a DAT section.
    The problem is: the DAT- initialization at compile time creates pointers without offset.

    Starting the program, I firstly change the pointers in the array with the @@ instruction in a loop one by one. That works.
    But I now wanted to transfer this to the called initialisation routine.

    Again the pointers are adjusted by adding 16. It works.

    But when I try to adjust the pointers with @@, (in the called start method), it doesn't

    Again the code:
    
    AnzScrePar = 80 ' The number of pointers in the array ProzScre
    Dat ProzScre long  @ScreCmd,  @ScVal002, @ActState, @Aktion  , @KeyBoCmd, @VersDate, @ScVal007, @ScVal008 '  1 -  8
                 long  @ScVal009, @ScVal010, @ScVal011, @ScVal012, @ScVal013, @DrehGeb , @ScVal015, @ScVal016 '  9 - 16
                 long  @ScVal017, @ScVal018, @ScVal019, @ScVal020, @ScVal021, @ScVal022, @ScVal023, @ScVal024 ' 17 - 24
                 long  @ScVal025, @ScVal026, @ScVal027, @ScVal028, @TimeDl1 , @TimeDl2 , @TimeDl3 , @TimeDl4  ' 25 - 32
                 long  @TimeDl5 , @TimeDl6 , @ScVal035, @ScVal036, @ScVal037, @ScVal038, @ScVal039, @Flg2Plt  ' 33 - 40
    
                 long  @PltVal_X, @PltValAr, @ScVal043, @ScVal044, @DrGeCmd , @DrehGebx, @ScVal047, @DrGeRes  ' 41 - 48
                 long  @DrGeVelo, @ScVal050, @ScVal051, @ScVal052, @ScVal053, @ScVal054, @ScVal055, @ScVal056 ' 49 - 56
                 long  @DrGeOfs,  @ScVal058, @ScVal059, @ScVal060, @ScVal061, @ScVal062, @ScVal063, @ScVal064 ' 57 - 64
                 long  @ScVal065, @ScVal066, @ScVal067, @ScVal068, @ScVal069, @ScVal070, @ScVal071, @ScVal072 ' 65 - 72
                 long  @ScVal073, @ScVal074, @ScVal075, @ScVal076, @ScVal077, @ScVal078, @DrGeVCnt, @DrGeVTim ' 73 - 80                   
    
    Pub  .....   'Program section
      ScreCmd := AnzScrePar                                 ' EN:".start" initializes "???Cmd" pointers
      i := Scre.start(@ProzScre) -1                         ' Screen process starten
    
    
    



    This allows me to simply pass as many addresses as necessary to the cog-process. And there is no limitation where these addresses point to and what the references types are.
    The pointers could be word because the memory is limited, but I don't care for that because the methods work both for spin and assembler.

    At that moment all the pointers in the array "ProzScre" are compile time initialized.

    The start method:
    CON
      AddrOffs = 16  ' A dirty solution to correct the Pointers to the global memory
    VAR
        byte ID_cog
    
    PUB Start( GlobPtr ) | i 
    
      Stop  ' Start can restart, therefore stop a possibly running cog first
      ' Create a local copy of the global pointer array and do the address correction "quick and dirty"
      repeat i from 0 to LONG[noparse][[/noparse]LONG[noparse][[/noparse]GlobPtr +   0]+AddrOffs]-1        ' The first parameter is the number of parameters
        LONG[noparse][[/noparse]@LoclPtr + (i<<2)] := LONG[noparse][[/noparse]GlobPtr + (i<<2)] + AddrOffs ' all pointers are 32 bit, the pointer address is byte oriented
          
      ifnot ID_cog
        ID_cog := cognew(@ASM_Entry, 0) + 1
      Result := ID_Cog 
    
    



    The repeat instruction now creates a local copy of the pointers and adds the offset to have the right runtime addresses.

    LONG[noparse][[/noparse]LONG[noparse][[/noparse]GlobPtr + 0]+AddrOffs] reads the number of pointers to copy.

    LONG[noparse][[/noparse]GlobPtr + 0]+AddrOffs is the address of that number. The " + 0" is just to indicate, that it is the first element of an array.
    I expected that @@LONG[noparse][[/noparse]GlobPtr + 0] would do the same job. But it doesn't and I didn't have the time to analyze the difference.

    The reason might be, that the called method has a different offset and that the @@ operator only works correctly in routine where the variables are defined.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    cmapspublic3.ihmc.us:80/servlet/SBReadResourceServlet?rid=1181572927203_421963583_5511&partName=htmltext
    Hello Rest Of The World
    Hello Debris
    Install a propeller and blow them away wink.gif
  • mparkmpark Posts: 1,305
    edited 2009-08-02 22:27
    You're right: @@ only works correctly in the object containing the variables. You could move Start to the main object with ProzScre etc., or you could compute the correct offset with "@@0" and pass it to Start, like this:
    Change
    i := Scre.start(@ProzScre) -1
    to
    i := Scre.start(@ProzScre, @@0) -1

    and in Scre:

    PUB Start( GlobPtr, AddrOffs ) | i
    (and delete CON AddrOffs = 16)
  • SamMishalSamMishal Posts: 468
    edited 2009-08-02 23:50
    mpark said...
    You're right: @@ only works correctly in the object containing the variables. You could move Start to the main object with ProzScre etc., or you could compute the correct offset with "@@0" and pass it to Start, like this:
    Change
    i := Scre.start(@ProzScre) -1
    to
    i := Scre.start(@ProzScre, @@0) -1

    and in Scre:

    PUB Start( GlobPtr, AddrOffs ) | i
    (and delete CON AddrOffs = 16)
    Goooood idea from MPark.........I think this would work very well for what you are trying to do.

    Another idea is to use an initialization method from within the object that contains the Dat section to adjust all the pointers before you
    call the start of the cog residing object and passing it the address of the pointers list. This will adjust the actual values of the pointers in
    the list before you use them in another object and thus you would not need to use the @@ at all from within the other object.
    You would just use the address value that they now contain which will be the right address since you have adjusted them
    using @@ from within the same object and all you would need is to derefrence it using Long[noparse]/noparse]Long[noparse][[/noparse]GlobalPtr][noparse][[/noparse]i.



    Samuel
    ·
  • ErNaErNa Posts: 1,752
    edited 2009-08-03 07:09
    @mpark: That is a clean solution. And: this should also work as a recursion. I will take care on that in the future. I didn't realize that @@ only works on the definition level. I wonder, if the linker couldn't do this job and make @@ obsolete. If there is no relative address mode, why it needs relative addresses? @@ could instead give a pointer to code and allow for calling by pointer wink.gif


    @Sam: initialization at start is possible and that is, what I did before. But I didn't like it for any reason. It's just stupid work ;.)

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    cmapspublic3.ihmc.us:80/servlet/SBReadResourceServlet?rid=1181572927203_421963583_5511&partName=htmltext
    Hello Rest Of The World
    Hello Debris
    Install a propeller and blow them away wink.gif
Sign In or Register to comment.