Shop OBEX P1 Docs P2 Docs Learn Events
Iteratively assigning cog variables from Main RAM — Parallax Forums

Iteratively assigning cog variables from Main RAM

How's it going everyone?

I've finished my VGA driver which is able to output a 640x480 VGA signal @ 60 Hz, compatible with both 8x8 and 16x16 tiles. In order to support this flexibility (as well as the ability to define custom screen tile dimensions and memory tile map dimensions) I calculate a fair number of attributes in the hub which are then passed to the VGA driver cog. Right now, I'm setting these internal registers in the following way (the full code can be viewed here):
' Initialize frame attributes
        mov             csl,    #0              ' Initialize upscale tracking register
        mov             attptr, par             ' Set attribute pointer        
        add             attptr, #4              ' Iterate through attributes and set external to internal equivalents        
        rdlong          vTilesH,attptr
        mov             numTL,  vTilesH
        add             attptr, #4
        rdlong          vTilesV,attptr
        mov             numTF,  vTilesV
        add             attptr, #4
        rdlong          tSizeH,attptr
        add             attptr, #4
        rdlong          tSizeV,attptr
        add             attptr, #4
        rdlong          tMapSizeH,attptr
        add             attptr, #4
        rdlong          tMapSizeV,attptr
        add             attptr, #4
        rdlong          tMemSizeH,attptr
        add             attptr, #4
        rdlong          tSize,attptr
        add             attptr, #4
        rdlong          tOffset,attptr
        add             attptr, #4
        rdlong          vLineSize,attptr
        add             attptr, #4
        rdlong          tMapLineSize,attptr
        add             attptr, #4
        rdlong          tlslRatio,attptr
        mov             slr,    tlslRatio
        sub             slr,    #1
        add             attptr, #4
        rdlong          lPerTile,attptr
        mov             numLT,  lPerTile
        add             attptr, #4
        rdlong          cPerFrame,attptr
        add             attptr, #4
        rdlong          cPerPixel,attptr
        add             attptr, #4
        rdlong          vSclVal,attptr

As you can see, this is hideous and it seems to me that it MUST be excessively explicit.

Is there a way to iteratively (i.e. using a loop) set internal cog registers? Thank you!

Comments

  • JonnyMacJonnyMac Posts: 9,104
    edited 2017-11-06 02:54
    Yes.

    In my rgbw pixel driver I have six variables than need to be passed to the PASM driver. The address of connection is passed in par.
      long  connection                                              ' compressed connection details
      long  resetticks                                              ' ticks in reset period
      long  rgfix                                                   ' swap r&g? + bit count for pixels
      long  t0h                                                     ' bit0 high time (ticks)      
      long  t1h                                                     ' bit1 high time (ticks)
      long  cycleticks                                              ' ticks in 1.25us
    

    And here's the top of my PASM code that copies moves these six values into the cog.
    pixdriver               mov     t1, par                         ' hub address of parameters -> t1
                            movd    :read, #connect                 ' location of cog parameters -> :read(dest)
                            mov     t2, #6                          ' get 6 parameters
    :read                   rdlong  0-0, t1                         ' copy parameter from hub to cog
                            add     t1, #4                          ' next hub element
                            add     :read, INC_DEST                 ' next cog element                         
                            djnz    t2, #:read                      ' done?
    

    I didn't create this strategy (Chip probably did) -- though I do take advantage of it.

    In your case, you might do something else. The loop moves the values from hub to cog, the next section takes care of the extra mov instructions. It's probably obvious, but your hub and cog variables must be laid out in the same order.
                            mov     t1, par
                            add     t1, #4         
                            movd    :read, #vTilesH 
                            mov     t2, #16          
    :read                   rdlong  0-0, t1         
                            add     t1, #4          
                            add     :read, INC_DEST 
                            djnz    t2, #:read
    
                            mov     numTL, vTilesH
                            mov     numTF, vTilesV     
                            mov     slr, tlslRatio
                            sub     slr, #1
                            mov     numLT, lPerTile
    
  • Have a look at vga.spin, it updates its cog registers from hub.
    '
    ' Tasks - performed in sections during invisible back porch lines
    '
    tasks                   mov     t1,par                  'load parameters
                            movd    :par,#_enable           '(skip _status)
                            mov     t2,#paramcount - 1
    :load                   add     t1,#4
    :par                    rdlong  0,t1
                            add     :par,d0
                            djnz    t2,#:load               '+164
    
    
  • One thing if you are running out of cog room: Since that code only gets executed once in its life, you can reuse the locations:
    ' Initialize frame attributes
    attptr  mov             csl,    #0              ' Initialize upscale tracking register
    vTilesH mov             attptr, par             ' Set attribute pointer        
    numTL   add             attptr, #4              ' Iterate through attributes and set external to internal equivalents        
    vTilesV rdlong          vTilesH,attptr
    numTF   mov             numTL,  vTilesH
    tSizeH  add             attptr, #4
    tSizeV  rdlong          vTilesV,attptr
    tMapSizeH mov             numTF,  vTilesV
    tMapSizeV add             attptr, #4
    etc    rdlong          tSizeH,attptr
            add             attptr, #4
            rdlong          tSizeV,attptr
            add             attptr, #4
            rdlong          tMapSizeH,attptr
            add             attptr, #4
    
    Especially hideous and obfuscating
  • roglohrogloh Posts: 5,787
    edited 2017-11-06 23:53
    One thing if you are running out of cog room: Since that code only gets executed once in its life, you can reuse the locations:

    Especially hideous and obfuscating

    Yeah although it's a particularly handy way to maximize the resources available in the COG.

    Actually I find that form of instruction space reuse after initialization not so bad. It gets a lot trickier when you have code being dynamically modified during its execution and registers being reused in different parts of the code for different purposes when they can be. Then deciphering the code and tracking problems down can become rather difficult, you need a lot of coffee for that. I've resorted to basically using all of those techniques in tight spots where you have to fit everything in the COG and get it to run in realtime - it's saved me quite a few times when writing video drivers etc where you also have to store a fair bit of data in the COG as well.

    I remember way back in undergrad Computer Science classes they would teach you that space can be traded for time in software. Once you try to wring everything out of a propeller chip in PASM that connection is clearly demonstrated.
  • Thanks for the outstanding help guys. The idea of overwriting instructions w/ memory is absolutely bizarre but awesome.
  • escherescher Posts: 138
    edited 2017-11-07 03:25
    JonnyMac wrote: »
    Yes.

    In my rgbw pixel driver I have six variables than need to be passed to the PASM driver. The address of connection is passed in par.
      long  connection                                              ' compressed connection details
      long  resetticks                                              ' ticks in reset period
      long  rgfix                                                   ' swap r&g? + bit count for pixels
      long  t0h                                                     ' bit0 high time (ticks)      
      long  t1h                                                     ' bit1 high time (ticks)
      long  cycleticks                                              ' ticks in 1.25us
    

    And here's the top of my PASM code that copies moves these six values into the cog.
    pixdriver               mov     t1, par                         ' hub address of parameters -> t1
                            movd    :read, #connect                 ' location of cog parameters -> :read(dest)
                            mov     t2, #6                          ' get 6 parameters
    :read                   rdlong  0-0, t1                         ' copy parameter from hub to cog
                            add     t1, #4                          ' next hub element
                            add     :read, INC_DEST                 ' next cog element                         
                            djnz    t2, #:read                      ' done?
    

    I didn't create this strategy (Chip probably did) -- though I do take advantage of it.

    In your case, you might do something else. The loop moves the values from hub to cog, the next section takes care of the extra mov instructions. It's probably obvious, but your hub and cog variables must be laid out in the same order.
                            mov     t1, par
                            add     t1, #4         
                            movd    :read, #vTilesH 
                            mov     t2, #16          
    :read                   rdlong  0-0, t1         
                            add     t1, #4          
                            add     :read, INC_DEST 
                            djnz    t2, #:read
    
                            mov     numTL, vTilesH
                            mov     numTF, vTilesV     
                            mov     slr, tlslRatio
                            sub     slr, #1
                            mov     numLT, lPerTile
    

    @JonnyMac you didn't mention you had a full walkthrough of this strategy: http://radio-hobby.org/uploads/journal/NV/2013/NV_09_2013.pdf

    That article is outstanding, and your code worked perfectly in my application.

  • JonnyMacJonnyMac Posts: 9,104
    edited 2017-11-07 17:46
    That article is outstanding, and your code worked perfectly in my application.
    Again, I simply followed the road paved by other programmers relative to transferring data from the hub to a cog.

    FWIW... I have made a lot of changes/improvements over the years to my pixel driver. The latest is in ObEx.
Sign In or Register to comment.