Shop OBEX P1 Docs P2 Docs Learn Events
Table of indirect address's — Parallax Forums

Table of indirect address's

bmentinkbmentink Posts: 107
edited 2013-08-06 14:53 in Propeller 1
Hi All,

I am trying to load some variables at run time from a table that holds their address's ... i.e the DAT section is
DAT
        DutyA long 0
        DutyB long 0
        DutyC long 0

        phases  long @DutyA, @DutyB, @DutyC
                long @DutyA, @DutyC, @DutyB
                long @DutyB, @DutyC, @DutyA
                long @DutyB, @DutyA, @DutyC
                long @DutyC, @DutyA, @DutyB
                long @DutyC, @DutyB, @DutyA

So the table holds the address of the variables, now my problem is how do I load up those variables via the table ..

I tried the following:
repeat i from 0 to 5
      long[@phases] [i*3] := 10
      long[@phases] [(i*3) +1] := 20
      long[@phases] [(i*3) +2] := 40

That did not do it ... then I discovered @@ so tried the following:
repeat i from 0 to 5
      @@phases[i*3] := 10
      @@phases[(i*3) +1] := 20
      @@phases[(i*3) +2] := 40

but all I got was a compile error ..

Can anyone help?

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-04 16:45
    If it's in the top object you can get away with this.
    DAT
            DutyA long 0
            DutyB long 0
            DutyC long 0
    
            phases  long @DutyA + 16, @DutyB + 16, @DutyC + 16
                    long @DutyA + 16, @DutyC + 16, @DutyB + 16
                    long @DutyB + 16, @DutyC + 16, @DutyA + 16
                    long @DutyB + 16, @DutyA + 16, @DutyC + 16
                    long @DutyC + 16, @DutyA + 16, @DutyB + 16
                    long @DutyC + 16, @DutyB + 16, @DutyA + 16
    

    Otherwise you will need a variable to hold the calculated offset.
      offset := @DutyA - phases[0] 
    

    You'd then add this offset to all references to the "phases" array.
  • bmentinkbmentink Posts: 107
    edited 2013-08-04 17:10
    Duane Degn wrote: »
    If it's in the top object you can get away with this.
    DAT
            DutyA long 0
            DutyB long 0
            DutyC long 0
    
            phases  long @DutyA + 16, @DutyB + 16, @DutyC + 16
                    long @DutyA + 16, @DutyC + 16, @DutyB + 16
                    long @DutyB + 16, @DutyC + 16, @DutyA + 16
                    long @DutyB + 16, @DutyA + 16, @DutyC + 16
                    long @DutyC + 16, @DutyA + 16, @DutyB + 16
                    long @DutyC + 16, @DutyB + 16, @DutyA + 16
    



    Can you please explain why you added + 16 to each address?
    I am in the top object, so how do I access the variables?

    Thanks
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-04 17:22
    bmentink wrote: »
    Can you please explain why you added + 16 to each address?
    I am in the top object, so how do I access the variables?

    Thanks

    I added 16 because that's what the "offset" variable would always equal as long as it's in the top object (based on prior experience).

    How you access the values will depend on what you're trying to do.

    x := long[phases][2] Edit: this is incorrect. See post #16

    will set x to whatever the value of "DutyC" is (in this case zero).

    If you were to use the offset variable (instead of adding 16 to each element) you'd access the same value with

    x := long[phases + offset][2] Edit: this is also incorrect.

    In the top object "offset" would equal 16. See post #16

    In this example, I assumed you wanted to access the third element (element "2") of the "phases" array.
  • bmentinkbmentink Posts: 107
    edited 2013-08-04 17:39
    Still doesn't explain where the magic number 16 comes from..... ;)
    Like my original example, I am trying to indirectly set the contents of DutyA,B,C via the table ... if I set the table with offest of 16 as you say then

    long[phases] [0] := 20
    long[phases] [1] := 40
    long[phases] [2] := 60

    .. works as intended, but

    long[phases] [3] := 20
    long[phases] [4] := 40
    long[phases] [5] := 60

    doesn't work! It seems only the 1st line in the table is available ..

    Also, I found that the following syntax works too (without the 16 offset in the table)

    long[@@phases] [0] := 20
    long[@@phases] [1] := 40
    long[@@phases] [2] := 60

    but again, only works for the 1st row ..

    [EDIT] It only works with the 1st 3 items, no matter how many there are in the row ..
  • Heater.Heater. Posts: 21,230
    edited 2013-08-04 18:10
    Thing is the @ operator in Spin is totally broken.
    It gives you different results depending of whether it is used in DAT sections to initialize things, as you do, or in Spin code.
    Neither are what you want which is the actual address in HUB RAM of whatever it is applied to.

    @@ does not help.

    That offset of 16 is there because @ returns the offset from the beginning of the object which is 16 in HUB RAM. Of course that only works if you are in the main, first, object.

    The BST Spin tool has a @@@ operator which does give you what you want but then you end up with code that Prop Tool users cannot use.
  • bmentinkbmentink Posts: 107
    edited 2013-08-04 19:14
    Heater. wrote: »
    Thing is the @ operator in Spin is totally broken.
    It gives you different results depending of whether it is used in DAT sections to initialize things, as you do, or in Spin code.
    Neither are what you want which is the actual address in HUB RAM of whatever it is applied to.

    @@ does not help.

    That offset of 16 is there because @ returns the offset from the beginning of the object which is 16 in HUB RAM. Of course that only works if you are in the main, first, object.

    The BST Spin tool has a @@@ operator which does give you what you want but then you end up with code that Prop Tool users cannot use.

    Hi Heater,

    Cool, I am using the BST tool, can you explain how to use the @@@ operator?
    Can I just do: long[@@@phases] [0] :=

    Cheers,
    B.
  • msrobotsmsrobots Posts: 3,709
    edited 2013-08-04 19:29
    I think you are missing something else here.

    you have 3 variables (longs)

    in your table you keep the addresses of those 3 longs multiple times

    so writing

    long[phases] [0] := 20
    long[phases] [1] := 40
    long[phases] [2] := 60
    will do the same as
    long[phases] [3] := 20
    long[phases] [4] := 40
    long[phases] [5] := 60
    will do the same as
    DutyA := 20
    DutyB := 40
    DutyC := 60

    what is the goal?

    Enjoy!

    Mike
  • bmentinkbmentink Posts: 107
    edited 2013-08-04 21:34
    msrobots wrote: »
    I think you are missing something else here.

    you have 3 variables (longs)

    in your table you keep the addresses of those 3 longs multiple times

    so writing

    long[phases] [0] := 20
    long[phases] [1] := 40
    long[phases] [2] := 60
    will do the same as
    long[phases] [3] := 20
    long[phases] [4] := 40
    long[phases] [5] := 60
    will do the same as
    DutyA := 20
    DutyB := 40
    DutyC := 60

    what is the goal?

    Enjoy!

    Mike

    No, not quite ...

    long[phases] [0] := 20
    long[phases] [1] := 40
    long[phases] [2] := 60

    DutyA := 20
    DutyB := 40
    DutyC := 60

    long[phases] [3] := 20
    long[phases] [4] := 40
    long[phases] [5] := 60

    DutyA := 20
    DutyB := 60 <--
    DutyC := 40 <-- swapped because Order of DutyB and C changed in table ..

    The goal is to load to DutyA .. C with a different order ... part of code for a six step BLDC motor ..

    I have simplified it somewhat for you guys ... the contents will be of course different than the constants I have shown. What is important, if you look at the table
    is the sequence ..

    Still don't have an answer for this ...
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-04 21:46
    bmentink wrote: »
    Still don't have an answer for this ...

    Can you attach an archive of your simplified code that shows this strange behavior? The problem might be elsewhere in the code.
  • bmentinkbmentink Posts: 107
    edited 2013-08-04 23:59
    Duane Degn wrote: »
    Can you attach an archive of your simplified code that shows this strange behavior? The problem might be elsewhere in the code.

    Not sure what you want ... the relevant code is in the 1st post, there is no other code to speak of ...

    I just need to know how to make a table of addresses of variables and then how to store data in the variables via the table (indirect addressing) .. if that is not clear to anyone, how do I make it clearer ??
  • Heater.Heater. Posts: 21,230
    edited 2013-08-05 02:54
    bmentink,
    I just need to know how to make a table of addresses of variables and then how to store data in the variables via the table
    Sounds clear enough.

    I think this works in BST:
    DAT
    
    ' Some variables to be pointed at by table of addresses.
    a long 1
    b long 2
    c long 3
    
    ' INCORRECT. table entries are relative to the object
    table1 long @a
           long @b
           long @c
    
    ' CORRECT, table entries are actual HUB addresses
    table2 long @@@a
           long @@@b
           long @@@c
    
    PUB start | x
        ' Read b indirectly through the table
        x := long[table2[1]]
    
        ' Write b indirectly through the table
        long[table2[1]] := x
    
        repeat
    


    Note that BST has a means of showing you a listing of what it compiles your code to so you can verify what addresses it actually puts in those tables. Just select the "Compiler Listing" option in the "View" menu before compiling your code and a listing window will appear.

    Now do you want to be changing those addresses in the table as you run?
  • ChrisGaddChrisGadd Posts: 310
    edited 2013-08-05 08:12
    You're trying to operate on one register (@phase_1[0]) that contains the address of a second register (@A+offset) that contains the value you want (A). Since there are two addresses you need to pass through, you need two long instructions:

    ' long[long[@phase_1][0]] := 21 ' set phase_1[0] to 21
    ' FDS.dec(long[long[@phase_1][0]]) ' display value in phase_1[0]

    Quick program to show the values in all of the phases.
    CON
      _clkmode = xtal1 + pll16x                                                   
      _xinfreq = 5_000_000
    
    OBJ
      FDS : "FullDuplexSerial"
      
    PUB Main | n
      FDS.start(31,30,0,115_200)
      waitcnt(cnt + clkfreq)
      FDS.tx($00)
    
      repeat 18 / 3
        FDS.str(string($0D,"Phase_"))
        FDS.dec(n / 3 + 1)
        FDS.tx($09)
        repeat 3
          FDS.dec(long[long[@phases[n++]]])
          FDS.tx($09)
    
    DAT       org
    A         long          20
    B         long          40
    C         long          60
    
    phases                                                               
    phase_1   long          @A+16,@B+16,@C+16
    phase_2   long          @A+16,@C+16,@B+16             
    phase_3   long          @B+16,@A+16,@C+16
    phase_4   long          @B+16,@C+16,@A+16
    phase_5   long          @C+16,@A+16,@B+16
    phase_6   long          @C+16,@B+16,@A+16
    
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-05 09:56
    ChrisGadd wrote: »
    You're trying to operate on one register (@phase_1[0]) that contains the address of a second register (@A+offset) that contains the value you want (A). Since there are two addresses you need to pass through, you need two long instructions:

    I'm going to have to think about this.

    I don't see a difference between "long[@phases[n++]]" and "phases[n++]".
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-05 10:00
    Either line works.
    'FDS.dec(long[long[@phases[n++]]])
          FDS.dec(long[phases[n++]])
    

    I personally think the second "long" is an unnecessary complication.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-05 10:03
    The "long[long[@" discussion made me realize my earlier error.

    This:
    [COLOR=#333333]x := long[phases][2][/COLOR]
    

    should have been this:
    [COLOR=#333333]x := long[phases[2]][/COLOR]
    
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-08-05 12:24
    I'm curious... could this not be solved with a CASE statement? The code might be a little longer, but certainly easier to follow end less prone to bugs. No?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-05 13:44
    I agree a case statement would probably be a better option in the example used so far, but I do think it can be very useful to store locations of other data in tables.

    In several of my touchscreen projects I list the various button parameters (location, color, text, etc) in a table. Here's an example (for TV control):
    channelUp0              byte 0, 5, _White, _Red, 0, _ChannelUp,                                    "   &#61600;   ", 0
    channelUp1              byte 0, 7, _White, _Red, 0, _ChannelUp,                                    "  Up   ", 0
    channelDown0            byte 0, 11, _White, _Green, 0, _ChannelDown,                               " Down  ", 0
    channelDown1            byte 0, 13, _White, _Green, 0, _ChannelDown,                               "   &#61602;   ", 0
    volumeUp0               byte 14, 5, _White, _Yellow, 0, _VolumeUp,                                 "   &#61600;   ", 0
    volumeUp1               byte 14, 7, _White, _Yellow, 0, _VolumeUp,                                 "  Up   ", 0
    volumeDown0             byte 14, 11, _White, _Green, 0, _VolumeDown,                               " Down  ", 0  
    volumeDown1             byte 14, 13, _White, _Green, 0, _VolumeDown,                               "   &#61602;   ", 0 
    vcrPower0               byte 7, 0, _White, _Red, 0, _VcrPower,                                     "  VCR  ", 0
    vcrPower1               byte 7, 2, _White, _Red, 0, _VcrPower,                                     " Power ", 0
    tvPower0                byte 0, 0, _White, _Yellow, 0, _TvPower,                                   "  TV   ", 0
    tvPower1                byte 0, 2, _White, _Yellow, 0, _TvPower,                                   " Power ", 0 
    boxPower0               byte 14, 0, _White, _Red, 0, _BoxPower,                                    "  Box  ", 0
    boxPower1               byte 14, 2, _White, _Red, 0, _BoxPower,                                    " Power ", 0 
    
    
    

    The list tell a method that creates the touch menu what buttons to put where and what they should say. "_BoxPower" indicates the action to perform. This "action" could be the address of another menu (if it were an address the action would require two bytes and the zero in the above examples would hold the upper byte of the address).

    The list of these buttons in stored elsewhere in the DAT section.
    menuTv                  word @channelUp0, @channelUp1, @channelDown0, @channelDown1, @volumeUp0, @volumeUp1, {
                            }    @volumeDown0, @volumeDown1, @vcrPower0, @vcrPower1, @tvPower0, @tvPower1, @boxPower0, {
                            }    @boxPower1, $003D, @menuOther, 0                                            
    

    This makes creating menus much easier since I just add the parameters of each button to the DAT section and list the buttons the menu is to use in other section.

    The menu one level higher than "menuTv" would have this as one of the buttons.
    tvButton0               byte 15, 11, _Green, _Yellow, (@menuTv / $100), @menuTv,                   " TV  ", 0
    tvButton1               byte 15, 13, _Green, _Yellow, (@menuTv / $100), @menuTv,                   "Menu ", 0
    
    
    

    When either of the above button locations is touched, it would launch the menu located at "@menuTv".

    The parameter "@menuTv" is passed to a method which generates the menu and monitors selections.

    I imagine there are other reasons one would want to list address in DAT section but I haven't found many myself. When it is useful to list address this way, I think it can be a very powerful tool.
  • AribaAriba Posts: 2,690
    edited 2013-08-05 17:47
    bmentink wrote: »
    Hi All,

    I am trying to load some variables at run time from a table that holds their address's ... i.e the DAT section is
    DAT
            DutyA long 0
            DutyB long 0
            DutyC long 0
    
            phases  long @DutyA, @DutyB, @DutyC
                    long @DutyA, @DutyC, @DutyB
                    long @DutyB, @DutyC, @DutyA
                    long @DutyB, @DutyA, @DutyC
                    long @DutyC, @DutyA, @DutyB
                    long @DutyC, @DutyB, @DutyA
    

    So the table holds the address of the variables, now my problem is how do I load up those variables via the table ..

    I tried the following:
    repeat i from 0 to 5
          long[@phases] [i*3] := 10
          long[@phases] [(i*3) +1] := 20
          long[@phases] [(i*3) +2] := 40
    

    That did not do it ... then I discovered @@ so tried the following:
    repeat i from 0 to 5
          @@phases[i*3] := 10
          @@phases[(i*3) +1] := 20
          @@phases[(i*3) +2] := 40
    

    but all I got was a compile error ..

    Can anyone help?

    You just overwrite your phase table and not the variables DutyA..C.

    With your table you can do it so:
    repeat i from 0 to 5
      long[@@phases[i*3+0]] := 10
      long[@@phases[i*3+1]] := 20
      long[@@phases[i*3+2]] := 40
    

    But why not store only the variable indexes in the phase table, like that:
    DAT
            Duty
            DutyA long 0
            DutyB long 0
            DutyC long 0
    
            phase1  long 0,0,1,1,2,2
            phase2  long 1,2,2,0,0,1
            phase3  long 2,1,0,2,1,0
    
    PUB...
    repeat i from 0 to 5
      Duty[phase1[i]] := 10
      Duty[phase2[i]] := 20
      Duty[phase3[i]] := 40
    
    This makes much more readable.

    Andy
  • bmentinkbmentink Posts: 107
    edited 2013-08-05 22:03
    Heater. wrote: »
    bmentink,


    Sounds clear enough.

    I think this works in BST:
    DAT
    
    ' Some variables to be pointed at by table of addresses.
    a long 1
    b long 2
    c long 3
    
    ' INCORRECT. table entries are relative to the object
    table1 long @a
           long @b
           long @c
    
    ' CORRECT, table entries are actual HUB addresses
    table2 long @@@a
           long @@@b
           long @@@c
    
    PUB start | x
        ' Read b indirectly through the table
        x := long[table2[1]]
    
        ' Write b indirectly through the table
        long[table2[1]] := x
    
        repeat
    


    Note that BST has a means of showing you a listing of what it compiles your code to so you can verify what addresses it actually puts in those tables. Just select the "Compiler Listing" option in the "View" menu before compiling your code and a listing window will appear.

    Now do you want to be changing those addresses in the table as you run?

    Wow, that's great .. worked a treat ..
    I have a 6-step 3-phase BLDC working great in open-loop now ... next step, to add sensorless commutation ..

    Cheers,
    B.
  • lonesocklonesock Posts: 917
    edited 2013-08-06 09:17
    When I need a table of address to work with the PropTool, I simply modify the pointer table once at runtime.
    DAT
    ' I'm encoding the length of the table at the beginning...you 
    ' will probably want to handle this in a different manner.
    strptrs word  5, @st1, @st2, @st3, @st4, @st5
    st1     byte  "This is my first string",0
    st2     byte  "This is my second string",0
    st3     byte  "This is my third string",0
    st4     byte  "This is my fourth string",0
    st5     byte  "This is my fifth string",0
    
    PRI update_strptrs : i
      ' only run this once
      if strptrs
        repeat i from 1 to strptrs
          strptrs[i] += @@0
        strptrs := 0
    
    PUB begin : p
    
      ' start up the serial interface, using the same hardware as the 
      ' programmer and at the fastest baud rate supported by hyperterm
      term.start( 31, 30, COMbps )
    
      update_strptrs
      repeat
        repeat p from 1 to 5
          term.str( strptrs[p] )
          term.tx( 13 )
          waitcnt( clkfreq + cnt )
    
    The modification subroutine needs to be in the same object as the data table, of course, or the '@@0' will be the wrong offset.

    Jonathan
  • Heater.Heater. Posts: 21,230
    edited 2013-08-06 11:49
    lonesock,

    Ah the "+= @@0" trick. I forgot about that.

    I really wonder on what planet that thing makes any sense. Seems to work though.

    Is it actually specified in the Spin language that it should work? I mean 0 is not any kind of location of any data in HUB to take the address of.
  • lonesocklonesock Posts: 917
    edited 2013-08-06 12:16
    If you tilt your head sideways and squint, you can sort of think maybe this is the object-relative address 0? I'm just glad it works. [8^) I can't find it in the prop manual or datasheet, and neither this forum's nor Google's search is any help given the weird characters "@@0".

    Jonathan
  • Heater.Heater. Posts: 21,230
    edited 2013-08-06 12:53
    lonesock,

    As far as I know their is no rigorous definition of Spin. As in syntax described in BNF or whatever. Never mind the semantics.

    So I guess anything might work.

    One of my favorites is:
    s long "hello" + "world"
    
    Who would guess what string of byte values that puts into a DAT section?
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-08-06 13:37
    Interesting -- and useless: each character is treated as a long.
  • lonesocklonesock Posts: 917
    edited 2013-08-06 14:06
    Yeah, weird...similar behavior to the lookdown(z) functions when you use a string.

    Jonathan
  • Heater.Heater. Posts: 21,230
    edited 2013-08-06 14:14
    Did I say "long" there I meant "byte".

    Weird stuff anyway.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-08-06 14:18
    Luckily, concatenation is handled by the compiler so this could be fixed. Right?
  • Heater.Heater. Posts: 21,230
    edited 2013-08-06 14:53
    Well, I guess it could be "fixed". However there is no Spin language specification against which we can say it is "broken".
    Then there is the risk that such a fix breaks some existing code. I bet there is someone out there who has used this "feature".

    Actually, thinking about it a bit, perhaps "string" + "string" should just be an error. I never did like + as a concatenation operator and it causes all kinds of confusion in languages like JavaScript.
Sign In or Register to comment.