Shop OBEX P1 Docs P2 Docs Learn Events
Yet another Global vs Local variables question across COGs — Parallax Forums

Yet another Global vs Local variables question across COGs

JackBakJackBak Posts: 45
edited 2009-10-16 13:44 in Propeller 1
Ok, lets keep this simple - no objects just one spin file. First COG is spin MAIN to fire off COG2 which is pure PASM.
Code is below. Note this is stub code so after the muxnc line nothing is going to work, I'm using the PASD tool to see
what is going on.

From what I can see q_pin through q_rpt are available in Main RAM to the COG1 spin code and when I fire off COG2
local versions of q_pin through q_rpt are instantiated. So in COG2 I get the global value of q_rpt by going thru an offset
from the par register. But if I simplify that idle loop by referencing q_rpt directly COG2 PASM code thinks it is the local
copy of q_rpt.

Notice that I can change q_rpt to a value of 2 by pressing a button on the Prop Professional Dev. Board (PPDB). When
I do that the main RAM version of q_rpt changes to 2 but unless I do the indexed par code below COG2 won't see
that new value of q_rpt.

{{ [b]test[/b] code }}

[b]CON[/b]
  [b]_clkmode[/b] = [b]xtal1[/b] + [b]pll16x[/b]
  [b]_xinfreq[/b] = 5_000_000

'*****************************************************************************
'  Global Definitions
'*****************************************************************************
  _OUTPUT       = 1             'Sets pin to output in DIRA register
  _INPUT        = 0             'Sets pin to input in DIRA register
  _HIGH         = 1             'High=ON=1=3.3v DC
  _ON           = 1
  _LOW          = 0             'Low=OFF=0=0v DC
  _OFF          = 0
  _ENABLE       = [b]true[/b]          'Enable (turn on) function/mode
  _DISABLE      = [b]false[/b]         'Disable (turn off) function/mode

'********************** L O C A L   C O N S T A N T S *************************
  BP            = 4             'Button pin
 
[b]OBJ[/b]
  dbg : "PasDebug"
  
[b]VAR[/b]
  [b]long[/b] Cog
  
[b]PUB[/b] Main | Time

   [b]dira[/b][noparse][[/noparse]*BP]~                                          'Input
   q_rpt := 0
   dbg.start(31, 30, @entry)
   Cog := [b]cognew[/b](@entry, @q_pin) + 1

  [b]repeat[/b]
    [b]if[/b] [b]ina[/b][noparse][[/noparse]*BP] == _LOW                                  'on button push light LED
      q_rpt := 2
      [b]dira[/b][noparse][[/noparse]*16]~~
      [b]outa[/b][noparse][[/noparse]*16] := _HIGH
      [b]waitcnt[/b]([b]cnt[/b] + (clkfreq / 1_000) * 3_000)         ' 3 seconds ON
      [b]outa[/b][noparse][[/noparse]*16] := _LOW                                 'LED off

[b]DAT[/b]
              [b]org[/b]       0

entry
'  --------- Debugger Kernel add this at Entry (Addr 0) ---------
   [b]long[/b] $34FC1202,$6CE81201,$83C120B,$8BC0E0A,$E87C0E03,$8BC0E0A
   [b]long[/b] $EC7C0E05,$A0BC1207,$5C7C0003,$5C7C0003,$7FFC,$7FF8
'  -------------------------------------------------------------- 
              [b]movd[/b]      :loop, #repeat_cnt
              [b]mov[/b]       tmp, [b]par[/b]
              [b]add[/b]       tmp, #16
:loop         [b]rdlong[/b]    0-0, tmp
              [b]test[/b]      repeat_cnt, #$FF [b]wz[/b]
      [b]if_z[/b]    [b]jmp[/b]       #:loop                  'we will wait for something to do
        
              [b]movd[/b]      parmld, #pin            'fall thru as we apparently have work to do
              [b]mov[/b]       p, [b]par[/b]
              [b]mov[/b]       j, #05
parmld        [b]rdlong[/b]    0-0, p
              [b]add[/b]       parmld, dlsb
              [b]add[/b]       p, #4
              [b]djnz[/b]      j, #parmld              'loop until we finish loading the parameters

              [b]mov[/b]       pmask, #1
              [b]shl[/b]       pmask, q_pin
              [b]muxnc[/b]     [b]dira[/b], pmask

              
                 
dlsb                    [b]long[/b]    1 << 9

q_pin   [b]long[/b]  $0A
q_pat   [b]long[/b]  $A5         'data pattern
q_win   [b]long[/b]  $12         'window for pattern
q_dly   [b]long[/b]  $34         'delay until next repeat of pattern
q_rpt   [b]long[/b]  $FF         'repeat count - if 0 driver loops waiting for non-zero

'
' Unitialized data
'
p             [b]res[/b]       1                       'parameter pointer
j             [b]res[/b]       1                       'counter
pmask         [b]res[/b]       1                       'pin mask
tmp           [b]res[/b]       1

pin           [b]res[/b]       1
pattern       [b]res[/b]       1
window        [b]res[/b]       1
delay         [b]res[/b]       1
repeat_cnt    [b]res[/b]       1





Thanks,

Jack

Comments

  • potatoheadpotatohead Posts: 10,261
    edited 2009-10-15 21:28
    If I understand you correctly, I think you are looking for associativity between HUB and COG memory. There isn't any. The local copy of the value will remain static, unless refreshed from the HUB value.

    If the COGs are to work together, they've got to pull the shared memory into their space to operate on it, or operate on the HUB value directly.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
    Safety Tip: Life is as good as YOU think it is!
  • JackBakJackBak Posts: 45
    edited 2009-10-15 21:33
    Indeed potatohead, I would like to reference directly the Hub version of q_rpt in the PASM COG2 code without
    having to go thru the PAR register and adding an index. Is this not possible to do except as I have shown? And yes,
    I know what you are referring to by letting the Main COG update a COG2 method - seems a bit much and too time expensive.

    Thanks,

    Jack
  • potatoheadpotatohead Posts: 10,261
    edited 2009-10-15 21:43
    Well, you could add the offset to the PAR register and just store it like a pointer. That way, it's just rdlong destination, pointer. One instruction refreshes the value that way.

    So, in your startup code, you might have something like the following:

    mov index, PAR

    rdlong value1, index
    mov value1_pointer, index
    add index, #4
    rdlong value2, index
    mov value1_pointer, index

    that way you capture your pointers when the cog gets up and running.

    In your DAT, you then have:

    value1 long 0
    value1_pointer long 0
    ...

    To update the cog, you do rdlong value1, value1_pointer

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
    Safety Tip: Life is as good as YOU think it is!

    Post Edited (potatohead) : 10/15/2009 9:51:13 PM GMT
  • JackBakJackBak Posts: 45
    edited 2009-10-15 21:48
    Yes possibly cleaner looking but isn't that what I'm really doing in the three lines starting at :loop ? Thanks, though
    I think I'm starting to read between the lines here. Probably do it this way and be done with it.

    Best regards,

    Jack.
  • AribaAriba Posts: 2,690
    edited 2009-10-16 01:44
    You can it simplify a bit, but you have to read the HubMemory to get the value of a Spin variable:
    '  --------- Debugger Kernel add this at Entry (Addr 0) ---------
       long $34FC1202,$6CE81201,$83C120B,$8BC0E0A,$E87C0E03,$8BC0E0A
       long $EC7C0E05,$A0BC1207,$5C7C0003,$5C7C0003,$7FFC,$7FF8
    '  -------------------------------------------------------------- 
                  mov       tmp, par
                  add       tmp, #16
    :loop         rdlong    repeat_cnt, tmp  wz
          if_z    jmp       #:loop                  'we will wait for something to do
    
                  movd      parmld, #pin            'fall thru as we apparently have work to do
                  ...
    
    



    Andy
  • JackBakJackBak Posts: 45
    edited 2009-10-16 03:12
    Thanks Andy, yeah I hadn't optimized it yet I was thinking of the TJZ opcode but hey your way is good too.

    Still kinda irritating that I have to do it with an index to PAR because it ties down the structure of the variables.
    I have to know the offset to hard code it into the ADD instruction. Linkers were made to keep track of things like
    this.

    Regards,

    Jack
  • AribaAriba Posts: 2,690
    edited 2009-10-16 03:26
    If you don't want hardcode the offset, I think this should work:
                  mov       tmp, par
                  add       tmp, #@q_rpt-@q_pin
    :loop         rdlong    repeat_cnt, tmp  wz
          if_z    jmp       #:loop                  'we will wait for something to do
                  ...
    
    



    Andy
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-10-16 06:32
    [b]CON
    [/b]  [b]_clkmode[/b] = [b]xtal1[/b] + [b]pll16x[/b]
      [b]_xinfreq[/b] = 5_000_000
    
    '*****************************************************************************
    '  Global Definitions
    '*****************************************************************************
      _OUTPUT       = 1             'Sets pin to output in DIRA register
      _INPUT        = 0             'Sets pin to input in DIRA register
      _HIGH         = 1             'High=ON=1=3.3v DC
      _ON           = 1
      _LOW          = 0             'Low=OFF=0=0v DC
      _OFF          = 0
      _ENABLE       = [b]true[/b]          'Enable (turn on) function/mode
      _DISABLE      = [b]false[/b]         'Disable (turn off) function/mode
    
    '********************** L O C A L   C O N S T A N T S *************************
      BP            = 4             'Button pin
     
    [b]OBJ[/b]
      dbg : "PasDebug"
      
    [b]VAR[/b]
      [b]long[/b] Cog
      
    [b]PUB[/b] Main | Time
    
       [b]dira[/b][noparse][[/noparse]&shy;BP]~                                          'Input
       q_rpt := 0
       dbg.start(31, 30, @entry)
       Cog := [b]cognew[/b](@entry, @q_[color=orange][s]pin[/s][color=green]rpt[/color][/color]) + 1
    
      [b]repeat[/b]
        [b]if[/b] [b]ina[/b][noparse][[/noparse]&shy;BP] == _LOW                                  'on button push light LED
          q_rpt := 2
          [b]dira[/b][noparse][[/noparse]&shy;16]~~
          [b]outa[/b][noparse][[/noparse]&shy;16] := _HIGH
          [b]waitcnt[/b]([b]cnt[/b] + (clkfreq / 1_000) * 3_000)         ' 3 seconds ON
          [b]outa[/b][noparse][[/noparse]&shy;16] := _LOW                                 'LED off
    
    [b]DAT[/b]
                  [b]org[/b]       0
    
    entry
    '  --------- Debugger Kernel add this at Entry (Addr 0) ---------
       [b]long[/b] $34FC1202,$6CE81201,$83C120B,$8BC0E0A,$E87C0E03,$8BC0E0A
       [b]long[/b] $EC7C0E05,$A0BC1207,$5C7C0003,$5C7C0003,$7FFC,$7FF8
    '  -------------------------------------------------------------- 
    [color=green]              jmp       #do_whatever              ' you can already start with the first execution here, as the variables q_... are already loaded from cognew. So, if[/color]
    [color=#008000]                                                  ' the variables are already initialized like they are in your code, you can start straight away.[/color]
     
    [color=green]:mainLoop[/color]
                  [color=red][s][b]movd[/b]      :loop, #repeat_cnt[/s]       ' it's a constant, so you can code it in rdlong directly[/color]
                  [b]mov[/b]       tmp, [b]par[/b]
                  [color=red][s][b]add[/b]       tmp, #16[/s]                 ' I'd simply change the order of the variables, then you don't have to add[/color]
    :loop         [b]rdlong[/b]    [s][color=orange]0-0[/color][/s][color=green]repeat_cnt[/color], tmp [color=green]wz   ' now you test for 0 in the read, but you only need this one instruction[/color]
                  [color=red][s][b]test[/b]      repeat_cnt, #$FF [b]wz[/b][/s]     ' [/color]
         [b]if_z[/b]    [b]jmp[/b]       #:loop                  'we will wait for something to do (namely as long as p_rpt in HUB-RAM is no longer zero
            
                  [b]movd[/b]      parmld, #[color=green][b]q_rpt[/b][/color][s]pin[/s]        'fall thru as we apparently have work to do
                                                      ' From this snippet of code I don't see a reason to have the RES variables. After cognew you have
                                                      ' all the q_-variables in COG-RAM, so why don't you use this memory later on?
                  [color=red][s][b]mov[/b]       p, [/s][b][s]par[/s]                 ' not needed, as par is already in tmp - use that[/b][/color]
                  [b]mov[/b]       j, #05
    parmld        [b]rdlong[/b]    0-0, p
                  [b]add[/b]       parmld, dlsb
                  [b]add[/b]       [color=orange][s]p[/s][/color][color=green]tmp[/color], #4
                  [b]djnz[/b]      j, #parmld              'loop until we finish loading the parameters
     
    [color=purple][color=green]do_whatever[/color]
                  mov       tmp, par                 ' this is needed to set the q_rpt of HUB-RAM to zero after loading the actual values. If you don't have this :loop will[/color]
    [color=purple]              wrlong    outb, tmp                ' always start reading the values. Or is $ff for pausing execution of the PASM from spin? Then don't add.
    [/color]
    
                  [b]mov[/b]       pmask, #1
                  [b]shl[/b]       pmask, q_pin
                  [b]muxnc[/b]     [b]dira[/b], pmask
    
                  
                     
    dlsb                    [b]long[/b]    1 << 9
    
    [color=green]q_rpt   [b]long[/b]  $FF         'repeat count - if 0 driver loops waiting for non-zero
    [/color]q_pin   [b]long[/b]  $0A
    q_pat   [b]long[/b]  $A5         'data pattern
    q_win   [b]long[/b]  $12         'window for pattern
    q_dly   [b]long[/b]  $34         'delay until next repeat of pattern
    [s][color=red]q_rpt   [b]long[/b]  $FF         'repeat count - if 0 driver loops waiting for non-zero
    [/color][/s]
    '
    ' Unitialized data
    '
    [s][color=red]p             [b]res[/b]       1                       'parameter pointer
    [/color][/s]j             [b]res[/b]       1                       'counter
    pmask         [b]res[/b]       1                       'pin mask
    tmp           [b]res[/b]       1
    
    [s][color=red]pin           [b]res[/b]       1
    pattern       [b]res[/b]       1
    window        [b]res[/b]       1
    delay         [b]res[/b]       1
    repeat_cnt    [b]res[/b]       1
    [/color][/s]
    


    So, my understanding is, that you want to run the PASM code straight away, as the q_-variables are already initialized in the code. If you don't use the RES variables in PASM, but the q_-variable-copies in COG-RAM, you don't waste 5 longs and you can start straight away without copying the values in the first place, because cognew already did that for you.
    I suppose after you repeated your code q_rpt-times, you go back to wait for q_rpt to be set again. But you have to clear it in HUB-RAM, otherwise your PASM might pick q_rpt from HUB-RAM before SPIN had a chance to set it to·0. Please remember: PASM is much faster than SPIN.

    Hope that helped.

    Post Edited (MagIO2) : 10/16/2009 6:38:32 AM GMT
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-10-16 07:19
    And remember if using the above method, 0 is not a legal value to be passed. If you are passing more than 1 long value, then make sure you clear it by pasm after you have copied all values, and likewise in spin (or another pasm cog) you set it last after setting all the other values.

    The main reason you have to use rd/wr/long/word/byte is because you have 16 bit addressing so you have to use indirect addressing (i.e. a pointer). Cog memory is limited to 9 bit addressing.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade, RetroBlade,·TwinBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: Micros eg Altair, and Terminals eg VT100 (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-10-16 09:43
    Hello MagIO2,

    I'm positive impressed ! Very good and detailed formatted source-code !
    best regards

    Stefan
  • JackBakJackBak Posts: 45
    edited 2009-10-16 13:44
    Excellent! Ok first off,

    @Andy:

    Yes it's all coming back to me (my assembler tricks that is)... let the compiler do the math #@q_rpt-@q_pin

    @MagIO2:

    Very nice, yes as I alluded to above I had not optimized anything and this was just stub code that I threw together
    to test concepts. I did think of putting q_rpt as the first variable in the block thus no index offset needed in the top idle loop.
    The reason I did not and in fact put it last was as a mental crutch to remind me that in any code I used to modify these
    hub variables I must change q_rpt to a non-zero last else the PASM driver would start executing on old data.
    My mental calculus was that since PASM code was plenty fast enough for this project I could tolerate the extra ADD offset.

    @Cluso99:

    Huh, why is zero illegal? Yes I had already thought about the sequence of setting variable see my comment above to MagIO2.
    [noparse][[/noparse]Edit] or did you mean illegal in the sense that that value in q_rpt would cause the driver to idle endlessly.


    Again really good stuff everyone thank you.

    Best regards,

    Jack

    Post Edited (JackBak) : 10/16/2009 1:59:24 PM GMT
Sign In or Register to comment.