Shop OBEX P1 Docs P2 Docs Learn Events
Of VAR and DAT — Parallax Forums

Of VAR and DAT

RicERicE Posts: 22
edited 2007-09-08 16:01 in Propeller 1
Hello,

I'm a complete newcomer to Propeller (I started my first experiments last week-end). However I have almost 30 years of programming and IT background, and plays for fun with µC (mainly ATMELs) since a few years now. OK, that was for my profile. Enough said now wink.gif A last detail : English is not my mother language, since I'm French. So apologizes in advance for approximative grammar and vocabulary....

First of all, I'm deeply amazed by the Propeller, and how it makes multi-thread programming on µC easy. Hats off for the Propeller creators.

To attempt fully understanding the inners of the beast (at SPIN level for the moment), I made several test with respect to data sharing between objects, COGs,... and the relation with declaring stuff using VAR or DAT.

As far as I could see with my tests, data declared in VAR section are "instantiated" for each reference to an object. In OO terms, I would qualify them as "instance data". On the opposite, data declared in DAT section are allocated once only. To re-use the OO parallel, they are like "static (or class leveol) data". Apart from that, from the inside of the object itself both can be used the same way (in terms of access)

My conclusion as a Propeller newbie, is that variables declared in DAT sections can be used to communicate between several instances of objects (accessing them from outside of the object with PUB methods of course), or to define values to be shared by all instances.

Here is a concrete example of this, based on one of my experiments :
- I wrote an object to interface an I2C LCD (same as the serial one used in several samples, but using I2C instead of serial com). This object references Basic_I2C_Driver provided in the libraries. Since all methods of Basic_I2C_Driver have a parameter specifying the pin driving the I2C SCL signal, I stored it in my I2C LCD object, so that callers of I2C LCD methods do not need to care with this, apart when invoking the LCD object initialization method
- from the top-level object running in COG0, I display periodic messages on it, using a reference to the LCD object
- another COG runs a code monitoring a push-button, to toggle the backlight of the LCD. Thus the button monitor object uses also the I2CLCD object.

To summarize, there are 2 instances of I2CLCD, one because of the reference from the top-level object, and the other because of the reference in the push-button monitor one.

I think that you start understanding where I'm going now. If the scl_pin variable is declared in the VAR section of I2CLCD, it will not work, since there will be 2 different "memory cells" for it, and it will not be initialized in the instance created via the reference from the button monitor object. I this variable is declared in DAT section, it works fine, so it seems to be shared between all object instances.

There is however something that remains not clear for me. From what I understood, the DAT part of an object is uploaded to the COG when cognew is invoked. Which is logic, since ASM code is executed directly from the COG RAM. But in this case, since the variables declared in DAT section are allocated in the COG RAM too, how can the sharing effect I could observe be possible ? Or maybe I've not understood correctly the mechanism, and what is uploaded to COGs is only the executable code. But this sounds me false, since it would then no be possible to have variables local to COGs.

The example is a bit artificial, but it is the prelude of a real prototype I am about to start. There will be several I2C devices in it, and the idea is to develop an object for each device, each of one referencing the I2C driver object. So I need to be sure that I2C level data will really be shared between all device objects.


Related to this project, I suspect I will have trouble if I2C device objects run in different COGs, since they will then manipulate the I2C signals in a non synchronized way. I understand that I need some mechanism to serialize I2C access, to be sure that each transaction is sane. What would be the right approach in such a situation ?


A last question now. I've seen in many example that the method commonly used to share data between COGs or objects was to pass a pointer of a memory area when initializing the object. So how does what I've noticed with DAT variable behaviors compare to this one ? Is my DAT variable technic just a "false good idea", working in my examples just because a hidden side effect I didn't realize, or can it be consider as valid ?


Many thanks in advance for any feedback.

Best regards

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Eric

More about my robotics related activities on : www.pobot.org

Post Edited (RicE) : 9/8/2007 11:15:09 AM GMT

Comments

  • RicERicE Posts: 22
    edited 2007-09-08 11:22
    Here is a small example exhibiting what I was talking about in my previous post :

    Top-level object, running in GOG0

    obj
      led[noparse][[/noparse] 3 ] : "led_control"
    
    pub main
      dira[noparse][[/noparse] 18 ] := 0                 ' button input
    
      led[noparse][[/noparse] 0 ].start(0)
      led[noparse][[/noparse] 1 ].start(1)
      led[noparse][[/noparse] 2 ].start(2)
    
      repeat
        led[noparse][[/noparse] 0 ].setState(ina[noparse][[/noparse] 18 ])
        waitcnt(clkfreq / 10 + cnt)                         ' pause for 1/10 sec
    
    



    LED control object :

    VAR
      long  stack[noparse][[/noparse] 9 ]
      byte  cog
    
    ' byte state
    
    PUB start(pin) : started
      stop
      started := (cog := cognew(run(pin), @stack) + 1)
    
    PUB stop
      if cog
        cogstop(cog~ - 1)
    
    PUB setState(_state)
      state := _state
      
    PRI run(pin)
      dira[noparse][[/noparse] pin ] := 1
      repeat
        outa[noparse][[/noparse] pin ] := state
        waitcnt(clkfreq / 10 + cnt)                         ' pause for 1/10 sec
    
    DAT
    state   byte  0
    
    



    In the configuration above, when pushing the button, all LEDs will change simultaneously. If the declaration of variable state is moved from DAT to VAR, only the LED connected to P0 will change (which is logic, since setState is called only for the instance of the LED control object managing P0 pin).

    Hope this will make my previous dissertation a bit easier to understand.

    Best regards

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Eric

    More about my robotics related activities on : www.pobot.org

    Post Edited (RicE) : 9/8/2007 11:42:43 AM GMT
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-08 11:23
    Eric,
    you have disclosed many important aspects of the "programming model" of SPIN, doubtlessly due to your background experience. And you must also be well aware that all this has been discussed many times in this forum during the last year as well smile.gif

    To summarize:
    From the point of view of SPIN interpretation you are correct in every respect; especially in addressing the "design flaw" that you cannot avoid an instantiation of another object, rather than using an already instantiated on.

    This "flaw" goes very deep. In fact it is connected to the unhappy fact, that you cannot have pointers to anything but variables, neither to routines ("methods") nor to modules ("objects").

    To further your understanding of communication between COGs and HUB memory:
    When you use SPIN, parallelism is accomplished by multiple copies of the SPIN interpreter in the COGs; there is nothing in the COGs but these "processors". All processed code ("SPIN") and variables are in the HUB.

    This is very clean model, supported by a stack mechanism and recursivly callable routines.!

    When you load your own machine code into a COG, this is different; you have to find all variables you need in the HUB, as a COG is a totally self contained machine.
    You can address the HUB be it ROM, DAT or VAR, as long as you know its (byte) address.

    The cells of the COG compriese a different (8 different!) address space, used by register addressing of the machine instructions. They are "pre-loaded" so to speak from HUB when starting the COG but are "detached" - so to speak - afterwards.

    I think it is best to think of the complete COG RAM as classical register space, which helps resolve some thinking knots tremendiously smile.gif

    But note there are additional pitfalls smile.gif
    E.g. I posted a nice article about the four (!) different kinds of the address operator (@) in SPIN the other day ...
    You might also profit from reading my "Machine Language Tutorial"; it will be updated tomorrow (I hope)

    Post Edited (deSilva) : 9/8/2007 11:29:19 AM GMT
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-08 11:36
    It's best to use a blank after each and every [noparse][[/noparse] ...
  • RicERicE Posts: 22
    edited 2007-09-08 11:39
    Hello deSilva,

    And many thanks for your quick reply.
    deSilva said...
    And you must also be well aware that all this has been discussed many times in this forum during the last year as well smile.gif

    I guessed it, and I can assure you that I spent hours reading the forum before writing my very first line of SPIN. But I could not browse all threads of course, and BTW I was not able at that time to understand all the details. I also download (among others) your document about assembly language, have read it, but not fully assimilated it (it requires and deserves more in depth readings). Since I have postponed assembly writing to some future, I didn't invest more. But knowing what you explained me, I will re-open it right after finishing this post wink.gif
    deSilva said...
    The cells of the COG compriese a different (8 different!) address space, used by register addressing of the machine instructions. They are "pre-loaded" so to speak from HUB when starting the COG but are "detached" - so to speak - afterwards.

    I have noticed this point when reading the documentation, but since the COG copy being "detached" after loading is complete, how can the sharing mechanism I observed be possible ? When the 3 additional COGs are running the LED control code (taken from the example of my second post), all behaves as if the sate variables declared in the DAT section were all at the same place in memory. I could understand this if the variable were allocated in HUB memory, and accessed from there from all COGs, by I understood that DAT variables were in COG "local" RAM. Where am I wrong ?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Eric

    More about my robotics related activities on : www.pobot.org

    Post Edited (RicE) : 9/8/2007 11:46:50 AM GMT
  • RicERicE Posts: 22
    edited 2007-09-08 11:41
    deSilva said...
    It's best to use a blank after each and every [noparse][[/noparse] ...

    Thanks for the tip wink.gif

    Post fixed now.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Eric

    More about my robotics related activities on : www.pobot.org
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-08 12:18
    RicE said...
    ....how can the sharing mechanism I observed be possible ? When the 3 additional COGs are running the LED control code (taken from the example of my second post), all behaves as if the sate variables declared in the DAT section were all at the same place in memory. I could understand this if the variable were allocated in HUB memory, and accessed from there from all COGs, by I understood that DAT variables were in COG "local" RAM. Where am I wrong ?

    I tried to explain....
    SPIN interpretation is a different kettle of fisch than running your own machine code!

    Doing SPIN, the COGs contain the interpreter(s) which work on HUB variables only.

    Running your own machine code you can EITHER consistently (!) use HUB variables - which is way slow and takes an extra instruction! - but ALSO the internal COG space which is 16 times faster - more or less.

    In fact you CAN NEVER MIX SPIN and assembly code!! It only looks so in the IDE, but you always have to use exclusively a COG for your own machine code and establish the necessary connections "by hand" (or "by PAR"- to be precise)
  • RicERicE Posts: 22
    edited 2007-09-08 12:56
    I think I'm starting to see the picture now.

    If I've correctly understood your explanations, and also after having re-read your (excellent) document about Propeller assembly, variables declared in DAT sections are accessed from their HUB memory location (the "image" which is uploaded to COGs during cognew) when used in SPIN, but are accessed from COG RAM when used in ASM. Thus the sharing behavior observed in my tests, since written exclusively in SPIN.

    Now, if I translate my LED object in ASM, it will not work the same way, because the state variable will now always been accessed from COG RAM.

    Is this correct ?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Eric

    More about my robotics related activities on : www.pobot.org
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-08 14:01
    RicE said...
    Now, if I translate my LED object in ASM, it will not work the same way, because the state variable will now always been accessed from COG RAM.
    Is this correct ?
    No smile.gif

    You have to decide what to access, there is no automatic or default mechanism....
    Accessing the HUB from a COG is an adventurious undertaking, with many pitfalls, and needs skillful planning ...

    O.k. it might be not that difficult, but I liked my phrase smile.gif

    Fact is, you have to organize the access to SPIN variables by providing the relevant addresses to the COG. I explained two ways in my tutorial:

    - Using PAR (COGNEW(@code, whatGoesIntoPAR_atLeast10bitsOfIt_generallyAnAddress)
    - Storing things into a piece of DAT garanted to be copied into the COG with the COGNEW

    I like the latter technique better, as it gives you more flexibility, and generally saves some COG code...

    BTW:
    The system routine COGNEW has two variants, and I regret they share the same name.... People say: But they do the same thing: loading code into a COG! True, true, but one version loads the SPIN interpreter and paranmetrizes it in a tricka way (and has a bug in that, as it cannot do that with a routine from another object); and the second versions loads YOUR CODE!

    COGNEW(myspin(1,2,3), @stack)

    This does NOT load "myspin" into a COG. This is quite obvious eventually, but it is misleading as long as your faith is still unsteady...

    Post Edited (deSilva) : 9/8/2007 2:06:20 PM GMT
  • LawsonLawson Posts: 870
    edited 2007-09-08 14:35
    when you have time, SerialMirror demonstrates how multiple instances of an object can act as a single shared object using DAT space.

    Marty

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Lunch cures all problems! have you had lunch?
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-08 14:41
    .. and he (implicitely) shows all the limits and issues smile.gif
    These are well known OOP strategies; the problem is that the (Propeller) FACTs are a little bit hidden
  • RicERicE Posts: 22
    edited 2007-09-08 14:43
    deSilva said...

    No smile.gif

    Gasp :-/
    deSilva said...

    You have to decide what to access, there is no automatic or default mechanism....

    Does it mean that, assuming the state variable is declared in the DAT section, I can use RDxxx/WRxxx on it, in addition to MOV et al ?
    deSilva said...

    - Storing things into a piece of DAT garanted to be copied into the COG with the COGNEW

    This is a "one shot" mechanism. Communication will occur at start time only, but if the HUB var is changed afterwards (like in my simple example), the COG code will not see it.

    So the only way to implement my example in ASM seems to use a RDBYTE in the ASM to get the status of the button.

    I think I have a better understanding of all this now, thanks to your kind support and your patience.

    Many thanks.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Eric

    More about my robotics related activities on : www.pobot.org
  • deSilvadeSilva Posts: 2,967
    edited 2007-09-08 15:00
    RicE said...
    Does it mean that, assuming the state variable is declared in the DAT section, I can use RDxxx/WRxxx on it, in addition to MOV et al ?
    Yes, the space used for the code and variables of the COG programm is HUB memory as any other.
    Imagine:
    - You can load a COG.
    - This COG modifies its original code (or preset data) in the HUB
    - When the COG is loaded a second time, it is a different program!

    (I add this just for safety: MOV only addresses into the segregated COG!)

    Also: You can carefully "recycle" the DAT memory. This is my favourate piece of code:
    Have a look here: http://forums.parallax.com/showthread.php?p=671300 .. the 28th posting I think smile.gif
    said...
    ... is a "one shot" mechanism. Communication will occur at start time only, but if the HUB var is changed afterwards (like in my simple example), the COG code will not see it.
    True! But there are possibilities...
    - Static parametrization
    - giving just an (or many!!) address(es)!

    The PAR mechanismen is limited to transfer one address only!
    said...
    So the only way to implement my example in ASM seems to use a RDBYTE in the ASM to get the status of the button.
    Yes, it is the only way.

    Have Fun!

    Post Edited (deSilva) : 9/8/2007 3:15:47 PM GMT
  • RicERicE Posts: 22
    edited 2007-09-08 16:01
    deSilva said...

    Yes, the space used for the code and variables of the COG programm is HUB memory as any other.
    Imagine:
    - You can load a COG.
    - This COG modifies its original code (or preset data) in the HUB
    - When the COG is loaded a second time, it is a different program!

    It reminds me the old days of Apple ][noparse][[/noparse] programming... So long ago now sad.gif
    deSilva said...

    True! But there are possibilities...
    - Static parametrization
    - giving just an (or many!!) address(es)!
    The PAR mechanismen is limited to transfer one address only!

    I too prefer the DAT preset method to the PAR one for passing parameters. It is simpler to use (no PAR increment when passing several data) and is more readable.

    I've now done a complete set of tests, experiencing all possible combinations (including the one involving COG ASM code : yes, I've written my first Propeller ASM code) and I think things are pretty clear for me now.

    In fact, I found all the answers to my initial questions in the last page (in fact, the before last, since the last one is the table of contents), and among others :
    deSilva said...

    Never forget: VAR is "object space"; only DAT is "global"!

    I've seen it during my first read, but before being facing real coding, it didn't hit my brain so much wink.gif. Your document really deserves (needs) several readings.

    However, I'm quite proud having found it by myself wink.gif As a side note, it has all its meaning when speaking about SPIN code, since DAT vars are accessible either from the HUB or the COG RAM from ASM, depending on the way used to access them.


    Thanks again for your help.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Eric

    More about my robotics related activities on : www.pobot.org
Sign In or Register to comment.